Skip to content
Platform · Visitors

Identify and track from your backend.

The widget covers browser-side identification. When the signal originates on your server — a signup, a billing webhook, an import — these routes write the same records without a browser in the loop.

The route most teams want

POST /api/widget/identify — the same route the widget uses, callable from any backend. It creates or updates the visitor's contact, links a company, and merges traits:

curl -X POST "https://api.chatwithhal.com/api/widget/identify" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "YOUR_PROJECT_ID",
    "user_id": "usr_123",
    "email": "mia@novaleaf.com",
    "name": "Mia Kovač",
    "company": { "name": "Nova Leaf", "domain": "novaleaf.com" },
    "metadata": { "plan": "trial", "seats": 8 }
  }'

Request fields

  • app_id (required) — the project the identity belongs to.
  • user_id — your stable identifier; the primary match key.
  • email — fallback match key; also becomes the contact's email.
  • name, company, metadata — written to the contact/company per the data model.
  • signature — HMAC hash when identity verification is on.
  • stage + stage_update_mode — optional CRM stage with advance_only (default) or exact semantics.

Set-properties for updates

Identify is for "this is who I am." For later property changes, use the visitor property routes — they merge single fields without resending the full identity:

PATCH /api/visitors/{id}     # update properties
GET   /api/visitors/{id}     # visitor with contact + company

Server-side events

POST /api/v1/events/track (public API key) records product events against a known customer. Use event_key for idempotency — retried webhooks from your billing provider won't double-count:

{
  "name": "plan.upgraded",
  "event_key": "sub_789_scale",
  "user_id": "usr_123",
  "value": 1800
}

Events feed automations ("usage limit reached" → lifecycle email), health signals, and the attribution view.

Write semantics

  • Matching order: user_id → email → create new.
  • Traits merge; the public API's metadata replaces (flat scalars, ≤ 10KB).
  • Company matching: domain first, then name.
  • Stage writes respect advance-only precedence unless exact is requested.

When to use which surface

  • Widget — the user is in the browser and already logged in.
  • Server identify — the identity was just established server-side (signup, SSO callback).
  • events/track — anything that happens in your product that should move a pipeline, trigger an email, or update health.