API Documentation

Reference docs for events ingestion, identity, and integration patterns.

Events API v2

v2 supports custom events and batch ingestion.

Event naming

Events use a two-part naming scheme:

  • event_type — entity noun (e.g. project, invite, billing)
  • action — verb describing what happened (e.g. created, sent, invoice_paid)

Both fields use snake_case: pattern ^[a-z][a-z0-9_]*$

Preferred format (recommended)

Send event_type and action as separate fields:

event_type action canonical_name
project created project_created
invite sent invite_sent
checkout abandoned checkout_abandoned
billing invoice_paid billing_invoice_paid

Unified event format (new)

Send a single event string. The server auto-splits it into event_type and action using the first separator found (dot, colon, or underscore):

event event_type action
user.signed_up user signed_up
billing:invoice_paid billing invoice_paid
project_created project created

No deprecation headers are returned for this format.

Legacy format (deprecated)

A flat event_type string without action is still accepted for backward compatibility.
The server auto-splits it (e.g. project_createdevent_type: "project", action: "created").

Legacy requests receive deprecation headers:

  • Deprecation: true
  • Sunset: 2026-09-01

Single event endpoint

POST /api/v2/events

Accepts:

  • event — unified event name with separator (one of event/event_type required)
  • event_type — entity noun (one of event/event_type required)
  • action — verb (omit for unified or legacy flat format)
  • subject_type (user, account, subscription)
  • subject_id
  • occurred_at
  • properties (object)
  • metadata (alias of properties)
  • external_id (idempotency key)

Example (preferred format)

bash
curl -X POST "/api/v2/events" \
  -H "Authorization: Bearer YOUR_EVENTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "project",
    "action": "created",
    "subject_type": "user",
    "subject_id": "user_123",
    "occurred_at": "2026-02-10T12:00:00Z",
    "properties": {
      "workspace_id": "ws_1",
      "template": "kanban"
    }
  }'

Response:

json
{
  "data": {
    "uuid": "evt_abc123",
    "event_type": "project",
    "action": "created",
    "canonical_name": "project_created",
    "source": "api",
    "subject_type": "user",
    "subject_id": "user_123",
    "occurred_at": "2026-02-10T12:00:00Z",
    "external_id": null
  }
}

Example (unified event format)

bash
curl -X POST "/api/v2/events" \
  -H "Authorization: Bearer YOUR_EVENTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "user.signed_up",
    "subject_type": "user",
    "subject_id": "user_123",
    "occurred_at": "2026-02-10T12:00:00Z",
    "properties": {
      "source": "organic",
      "plan": "free"
    }
  }'

Batch endpoint

POST /api/v2/events/batch

Use this for higher throughput and fewer network round-trips.

Example

bash
curl -X POST "/api/v2/events/batch" \
  -H "Authorization: Bearer YOUR_EVENTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "event_type": "invite",
        "action": "sent",
        "subject_type": "user",
        "subject_id": "user_1",
        "occurred_at": "2026-02-10T12:00:00Z",
        "external_id": "evt_1",
        "properties": { "channel": "email" }
      },
      {
        "event_type": "invite",
        "action": "accepted",
        "subject_type": "user",
        "subject_id": "user_2",
        "occurred_at": "2026-02-10T12:00:10Z",
        "external_id": "evt_2",
        "properties": { "channel": "email" }
      }
    ]
  }'

Example (batch with unified event format)

bash
curl -X POST "/api/v2/events/batch" \
  -H "Authorization: Bearer YOUR_EVENTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "event": "feature.enabled",
        "subject_type": "user",
        "subject_id": "user_1",
        "occurred_at": "2026-02-10T12:00:00Z"
      },
      {
        "event": "feature.disabled",
        "subject_type": "user",
        "subject_id": "user_2",
        "occurred_at": "2026-02-10T12:00:10Z"
      }
    ]
  }'

Idempotency

Use external_id to safely retry requests.

Deduplication is scoped by:

  • product
  • source
  • external_id