Events API
Events are the primary data ingestion point for Synapse. Your application sends events when users take actions (sign up, purchase, page view), and Synapse uses these events to trigger flows, update contact profiles, and drive analytics.
For a platform guide on events, see Events. For authentication details, see Authentication.
Authentication
Events API uses API key authentication with the data scope.
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/events | Ingest a single event |
POST | /v1/events/batch | Ingest up to 50 events in one request |
GET | /v1/events | List events (JWT auth, dashboard) |
GET | /v1/events/{id} | Get event details (JWT auth, dashboard) |
POST | /v1/events/trigger | Trigger a test event (JWT auth, dashboard) |
POST | /v1/events/{id}/retrigger | Re-trigger flow processing for an event (JWT auth, dashboard) |
Ingest Event
POST /v1/events
Auth: API key (data scope)
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
event_name | string | Yes | Snake-case event name (e.g., purchase_completed) |
external_id | string | Yes | Your application's user ID for the contact |
attributes | object | No | Event-specific data (used in templates and conditions) |
contact_overrides | object | No | Update contact fields (email, first_name, last_name, phone, properties) |
idempotency_key | string | No | Prevents duplicate processing (7-day TTL) |
timestamp | string | No | ISO 8601 timestamp (defaults to server time) |
Response (202 Accepted)
Events are processed asynchronously. A 202 Accepted response means the event has been queued for processing, not that flows have been triggered yet.
Batch Ingest
POST /v1/events/batch
Auth: API key (data scope)
Send up to 50 events in a single request. Each accepted event counts as 1 event against your monthly limit, but the entire batch counts as 1 request against the rate limit.
The batch endpoint is partial-accept: each event is validated and ingested independently, so one bad event no longer fails the whole batch. Valid events land even when a sibling event is malformed or over the plan limit.
Request Body
Each event follows the same schema as POST /v1/events. The events array must contain 1 to 50 items. A batch that is malformed as a whole — missing the events key, events is not an array, or more than 50 items — is rejected with 422 at the request boundary before any event is processed.
Response header opt-in
Send the X-Synapse-SDK-Version: 2 request header to receive the structured, per-event partial-accept response body. Clients that omit the header get the legacy response shape (see Legacy clients below). The Browser SDK sends this header automatically from version 0.5.0.
Response (202 Accepted) — with X-Synapse-SDK-Version: 2
Returned when at least one event was accepted. rejected is a list of the events that did not land, each tagged with the original 0-based index in your events array and a machine-readable reason.
| Field | Type | Description |
|---|---|---|
accepted | integer | Number of events accepted and queued for processing |
rejected | array | One entry per event that was not accepted (empty array when all accepted) |
rejected[].index | integer | 0-based position of the event in the submitted events array |
rejected[].reason | string | Rejection reason — one of invalid_schema, over_limit, runtime_error |
rejected[].detail | string | null | Human-readable detail for invalid_schema — the raw validation message (multi-line, may be verbose); null for over_limit. Treat it as a diagnostic aid to log, not a stable string to parse. |
Rejection reasons:
| Reason | Meaning | Should you retry? |
|---|---|---|
invalid_schema | The event failed validation (missing required field, bad type). | No — it can never succeed. Fix your instrumentation. |
over_limit | The event is valid, but your workspace's monthly events quota was reached before this event could be counted. | Yes, later — retry after your quota resets or you upgrade. |
runtime_error | An unexpected server-side error occurred while ingesting this specific event. | Yes — safe to retry. |
Status matrix
| Outcome | Status | Body |
|---|---|---|
| At least one event accepted | 202 Accepted | Partial-accept body (accepted count + any rejections) |
Zero accepted, all rejections are invalid_schema | 422 Unprocessable Content | Partial-accept body |
Zero accepted, any rejection is over_limit | 403 Forbidden | plan_limit_reached error (see below) |
When every event in a batch is over the plan limit (nothing accepted), the response is a 403 with the standard plan-limit error shape:
Legacy clients (no version header)
Clients that do not send X-Synapse-SDK-Version receive the original response shape, where rejected is a count — byte-identical to the pre-partial-accept response:
Plan-limit behavior differs for legacy clients. A legacy client whose batch would partially exceed the monthly events quota receives a 403 plan_limit_reached for the whole batch — rather than a 202 that silently drops the over-limit events. This is deliberate: an older client that re-queues on 4xx will retry the whole batch later instead of losing data. Send X-Synapse-SDK-Version: 2 to instead get a 202 with the accepted events plus over_limit entries you re-queue yourself.
Events are queued for asynchronous processing. A 202 Accepted (or the accepted count) means the event was queued, not that flows have been triggered yet.
List Events (Dashboard)
GET /v1/events
Auth: JWT (dashboard). Requires events:read permission.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
search | string | Search by event name or external ID | |
event_name | string | Filter by event name | |
limit | integer | 50 | Max items per page (max 100) |
offset | integer | 0 | Pagination offset |
Plan Limits
| Plan | Monthly Events |
|---|---|
| Free | 10,000 |
| Starter | 100,000 |
| Growth | 1,000,000 |
| Enterprise | Unlimited |
Exceeding the monthly event limit returns 403 with code plan_limit_reached.