Timeline API in PHP Package

We want to create events, but we cant get the code to work.

$hubSpotClient->create()->crm()->timeline()->eventsApi()->create(
 new TimeLineEvent([
 'event_template_id' => '137246454',
 'object_id' => $companyId,
 ]);

We get an error with a message “Some eventTemplateIds do not exist”, which suggests, that we did not have setup an event template properly, or may use a wrong id.
The $hubspotClient ist initiated like this

Factory::createWithAccessToken($this->hubSpotAPIKey);

and works with Contacts, Companies and Associatians API.
In Hubspot GUI, we have added “timeline” to the scope of our “Private App”/Integration.
We see some of the errors we make, which go following endpoint:
/integrators/timeline/v3/events
The events are created in “Custom Events”->Create
- Send Via API
- Associated Object: Companies
- No custom properties
Then we get a trackingId in the format “pe123456789_eventName”. But neither that, or the $ID from the url of the edit/details page.
https://app-eu1.hubspot.com/events/**********/manage/$ID/overview seem to qualify as “event_template_id”.

-------

After that, we tried to use the Templates API and just look, if we get other eventTemplateIds of those created in the GUI (if setup was right)

$this->hubSpotClient->create()->crm()->timeline()->templatesApi()->getAll($accountId);

There, we get a 401 error, stating “Any of the listed authentication credentials are missing”.
When researching the api/developer docs, knowledge base articles, it seems the Timeline API and GUI have changed and are not up to date or even synced.
E.g. why isnt there a distinction between event and event template in the gui anymore?

Hi, @SweDev :waving_hand: 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

Thanks for your detailled reply.

So I need a dedicated Hubspot Developers Account to use the Templates API?
Because we have just regular Hubspot accounts (prod & test) with the above mentioned APIs working.
Can we link those after creation? Or how do we connect the created private apps?
Also what are the Custom Events good for in the regular Hubspot GUI (with “Send via API” option), if not for this particular usecase?