API referencev1

Send signals

POST /track, the call everything else depends on.

POST /track

curl -X POST "https://api.thepulseapi.com/api/v1/track" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_..." \
  -d '{
    "sessionId": "sess_abc123",
    "organizationId": "org_abc123",
    "signals": [
      { "type": "category_view", "value": "helmets-safety" },
      { "type": "price_filter", "value": "500000-1500000" }
    ]
  }'

With the SDK:

await pulse.track([
  { type: 'category_view', value: 'helmets-safety' },
  { type: 'price_filter', value: '500000-1500000' },
]);

Signals are additive. Send them as they happen rather than batching a whole session at the end: persona scores decay, so ordering carries meaning.

organizationId is required

Every endpoint below reads it from the body, not from the API key. Omitting it returns 400 with a validation error naming the field. The SDK sends it for you from init().

/track also captures device, referrer and time from the request itself, so a call with no signals at all is still worth making: it opens the session with what the request already says.

POST /track/behavior

One behaviour, named, when you have nothing to say about a category or a price.

curl -X POST "https://api.thepulseapi.com/api/v1/track/behavior" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_..." \
  -d '{
    "sessionId": "sess_abc123",
    "organizationId": "org_abc123",
    "behavior": "sort_price_asc",
    "metadata": { "page": "category" }
  }'

behavior is your own slug, capped at 128 characters. Sorting by price ascending says something about a shopper that no category view does.

POST /track/keywords

A search query, turned into keyword signals for you.

curl -X POST "https://api.thepulseapi.com/api/v1/track/keywords" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_..." \
  -d '{
    "sessionId": "sess_abc123",
    "organizationId": "org_abc123",
    "query": "mu bao hiem fullface"
  }'

Send the raw query. Extraction happens server-side, and the query is capped at 512 characters because the work is linear in its length.

POST /event

A named event, for things that are not persona signals.

await pulse.event('checkout_started', { cartValue: 1250000 });

On this page