Hi, @SweDev
Thanks for your questions. I’m going to take a step back and break out the steps needed to successfully use these endpoints.
Here’s the breakdown. (Detailed instructions and examples below)
Phase 1: Development Setup
1. App Developer Account (developers.hubspot.com)
2. Developer API Key
3. Public App Creation
- Required scope: timeline
- Note your App ID
Phase 2: Template Management (Using Developer API Key)
1. Create Template
- Uses Developer API Key
- Uses Public App ID
- Returns template ID (crucial for later)
2. Verify Templates
- Query existing templates
- Confirm template creation
- Note template IDs
Phase 3: Testing Environment (Recommended)
1. Developer Test Account Setup
2. Install your app in test account
3. Create Private App in test account
4. Test event creation
Phase 4: Production Implementation
1. Install app in production portal
2. Create Private App in production
3. Use template IDs with Private App token
4. Create events
Setup:
Create an App Test Account
Create a Public App (you’ll need the App ID in a sec)
Locate your Developer API key
Creating your Template:
Let’s use the on-page example to create a template for our app
You’ll need your Public App ID and your Developer API Key
<?php
use HubSpot\Factory;
use HubSpot\Client\Crm\Timeline\ApiException;
use HubSpot\Client\Crm\Timeline\Model\TimelineEventTemplateCreateRequest;
use HubSpot\Client\Crm\Timeline\Model\TimelineEventTemplateToken;
use HubSpot\Client\Crm\Timeline\Model\TimelineEventTemplateTokenOption;
$client = Factory::createWithDeveloperApiKey('YOUR_DEVELOPER_API_KEY');
$timelineEventTemplateToken1 = new TimelineEventTemplateToken([
'name' => 'petName',
'label' => 'Pet Name',
'type' => 'string'
]);
$timelineEventTemplateToken2 = new TimelineEventTemplateToken([
'name' => 'petAge',
'label' => 'Pet Age',
'type' => 'number'
]);
$timelineEventTemplateTokenOption1 = new TimelineEventTemplateTokenOption([
'label' => 'White',
'value' => 'white'
]);
$timelineEventTemplateTokenOption2 = new TimelineEventTemplateTokenOption([
'label' => 'Black',
'value' => 'black'
]);
$timelineEventTemplateTokenOption3 = new TimelineEventTemplateTokenOption([
'label' => 'Brown',
'value' => 'brown'
]);
$timelineEventTemplateTokenOption4 = new TimelineEventTemplateTokenOption([
'label' => 'Other',
'value' => 'other'
]);
$options1 = [
$timelineEventTemplateTokenOption1,
$timelineEventTemplateTokenOption2,
$timelineEventTemplateTokenOption3,
$timelineEventTemplateTokenOption4
];
$timelineEventTemplateToken3 = new TimelineEventTemplateToken([
'options' => $options1,
'name' => 'petColor',
'label' => 'Pet Color',
'type' => 'enumeration'
]);
$timelineEventTemplateCreateRequest = new TimelineEventTemplateCreateRequest([
'detail_template' => 'Registration occurred at {{#formatDate timestamp}}{{/formatDate}}
#### Questions
{{#each extraData.questions}}
**{{question}}**: {{answer}}
{{/each}}',
'name' => 'PetSpot Registration',
'tokens' => [$timelineEventTemplateToken1, $timelineEventTemplateToken2, $timelineEventTemplateToken3],
'header_template' => 'Registered for [{{petName}}](https://my.petspot.com/pets/{{petName}})',
'object_type' => 'contacts',
]);
try {
$apiResponse = $client->crm()->timeline()->templatesApi()->create(100, $timelineEventTemplateCreateRequest);
var_dump($apiResponse);
} catch (ApiException $e) {
echo "Exception when calling templates_api->create: ", $e->getMessage();
}
Response
HTTP 201
{
"name": "PetSpot Registration",
"headerTemplate": "Registered for [{{petName}}](https://my.petspot.com/pets/{{petName}})",
"detailTemplate": "Registration occurred at {{#formatDate timestamp}}{{/formatDate}}\n\n#### Questions\n{{#each extraData.questions}}\n **{{question}}**: {{answer}}\n{{/each}}",
"tokens": [
{
"label": "Pet Name",
"objectPropertyName": null,
"options": [],
"name": "petName",
"type": "string",
"createdAt": "2025-01-08T16:14:39.587Z",
"updatedAt": "2025-01-08T16:14:39.587Z"
},
{
"label": "Pet Age",
"objectPropertyName": null,
"options": [],
"name": "petAge",
"type": "number",
"createdAt": "2025-01-08T16:14:39.594Z",
"updatedAt": "2025-01-08T16:14:39.594Z"
},
{
"label": "Pet Color",
"objectPropertyName": null,
"options": [
{
"value": "white",
"label": "White"
},
{
"value": "black",
"label": "Black"
},
{
"value": "brown",
"label": "Brown"
},
{
"value": "other",
"label": "Other"
}
],
"name": "petColor",
"type": "enumeration",
"createdAt": "2025-01-08T16:14:39.600Z",
"updatedAt": "2025-01-08T16:14:39.600Z"
}
],
"id": "2024583",
"objectType": "contacts",
"createdAt": "2025-01-08T16:14:39.575Z",
"updatedAt": "2025-01-08T16:14:39.575Z"
}
Query existing Templates:
Use this endpoint along with your Developer API Key and App ID
Request
<?php
use HubSpot\Factory;
use HubSpot\Client\Crm\Timeline\ApiException;
$client = Factory::createWithDeveloperApiKey('YOUR_DEVELOPER_API_KEY');
try {
$apiResponse = $client->crm()->timeline()->templatesApi()->getAll(819779);
var_dump($apiResponse);
} catch (ApiException $e) {
echo "Exception when calling templates_api->get_all: ", $e->getMessage();
}
Response
HTTP 200
{
"results": [
{
"name": "PetSpot Registration",
"headerTemplate": "Registered for [{{petName}}](https://my.petspot.com/pets/{{petName}})",
"detailTemplate": "Registration occurred at {{#formatDate timestamp}}{{/formatDate}}\n\n#### Questions\n{{#each extraData.questions}}\n **{{question}}**: {{answer}}\n{{/each}}",
"tokens": [
{
"label": "Pet Age",
"objectPropertyName": null,
"options": [],
"name": "petAge",
"type": "number",
"createdAt": "2025-01-08T16:14:39.594Z",
"updatedAt": "2025-01-08T16:14:39.594Z"
},
{
"label": "Pet Color",
"objectPropertyName": null,
"options": [
{
"value": "black",
"label": "Black"
},
{
"value": "brown",
"label": "Brown"
},
{
"value": "other",
"label": "Other"
},
{
"value": "white",
"label": "White"
}
],
"name": "petColor",
"type": "enumeration",
"createdAt": "2025-01-08T16:14:39.600Z",
"updatedAt": "2025-01-08T16:14:39.600Z"
},
{
"label": "Pet Name",
"objectPropertyName": null,
"options": [],
"name": "petName",
"type": "string",
"createdAt": "2025-01-08T16:14:39.587Z",
"updatedAt": "2025-01-08T16:14:39.587Z"
}
],
"id": "2024583",
"objectType": "contacts",
"createdAt": "2025-01-08T16:14:39.575Z",
"updatedAt": "2025-01-08T16:14:39.575Z"
}
]
}
Optional but recommended*
- Create a Developer Test Account
- Install your app
- Generate a Private App (auth for using the Create Events endpoint)
- Use this endpoint to test creating custom timeline events in your Test Account (this allows you to test your app without affecting your production portal)
In summary
- To use this tool, you’ll need:
- An app developer account
- A developer API key
- A public app
- (*optional) Developer Test Account- to install app and test creating timeline events without affecting your production portal
Once all that is created and set up, then you can use your Private App to create the events for its specific portal.
Have fun testing! — Jaycee