Events
| Method | Path | Scope | SDK |
|---|---|---|---|
POST | /api/v1/events | sequences:write | events.track |
One call does four things: upserts the contact, enrolls them into every active
sequence whose trigger equals type, re-arms flows waiting on that event, and
cancels their enrollments in the sequences you list under exitSequences.
Request
| Field | Type | Notes |
|---|---|---|
type | string | Required. Your event name, e.g. order.placed. Matched against each sequence's trigger. |
email | string | Required unless contactId is given; upserted if unknown. |
contactId | uuid | Address an existing contact instead. |
data | object | Event payload. Available to templates and branch conditions. |
exitSequences | string[] | Sequence keys to cancel active enrollments in. |
curl -X POST https://mailroom.example.com/api/v1/events \
-H "Authorization: Bearer pk_live_…" \
-H "Content-Type: application/json" \
-d '{
"type": "order.placed",
"email": "ada@example.com",
"data": { "orderId": "ord_123", "total": 4200, "currency": "USD" },
"exitSequences": ["abandoned-cart"]
}'
Response
{ "ok": true, "contactId": "9f0c…", "enrolled": 1, "reArmed": 0, "exited": 1 }
Counts, not ids:
enrolled— new enrollments started by this event.reArmed— waiting enrollments that this event advanced.exited— enrollments cancelled viaexitSequences.
All zeros is a normal outcome: it means no active sequence is triggered by that
type. The contact upsert still happened.
Errors
| Status | code | Cause |
|---|---|---|
| 422 | invalid_request | Missing type, or neither email nor contactId |
| 422 | reason string | The event could not be applied (e.g. the contact is unsubscribed) |
| 403 | forbidden | Key lacks sequences:write |
Notes
- Event names are free-form. Nothing validates
type, so a typo silently triggers nothing — keep the string in one constant on your side. - Not idempotent by nature. Two identical calls can create two enrollments where
re-entry allows it. Send an
Idempotency-Keyheader when replaying. - Events are not analytics. Mailroom keeps them to drive automation, not to be queried back; there is no event-read endpoint.