Events API v2
Compatibility disposition review — 2026-09-05: this retained contract advertises a legacy-input
Sunset: 2026-09-01; the cited changelog does not record whether removal occurred, was extended, or was abandoned. That disposition is unresolved here. The responsible API maintainer must reconcile an exact server release and compatibility tests before asserting support/removal or changing clients. No endpoint was exercised by this review. Other v2 contract sections are not blanket-superseded by this uncertainty; see the docs map.
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)
The pre-sunset contract accepts a flat event_type string without action for backward compatibility and auto-splits it (e.g. project_created → event_type: "project", action: "created"). Continued acceptance after the advertised date is not established by this note.
Documented pre-sunset legacy response headers:
Deprecation: trueSunset: 2026-09-01
Single event endpoint
POST /api/v2/events
Accepts:
event— unified event name with separator (one ofevent/event_typerequired)event_type— entity noun (one ofevent/event_typerequired)action— verb (omit for unified or legacy flat format)subject_type(user,account,subscription)subject_idoccurred_atproperties(object)metadata(alias ofproperties)external_id(idempotency key)
Example (preferred format)
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:
{
"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)
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
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)
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