Guides
Send events
Post an event once and let Dispatch fan it out to every subscribed customer endpoint.
Sending is one authenticated POST. Dispatch checks the event, finds the endpoints that should receive it, and queues one delivery for each.
curl -X POST https://api.getensue.com/v1/dispatch/events \
-H "authorization: Bearer ens_live_…" -H "content-type: application/json" \
-H "idempotency-key: order-1042-shipped" \
-d '{
"type": "order.shipped",
"customer": "acme",
"data": { "order_id": "1042", "carrier": "UPS" }
}'
Request
| Field | Notes |
|---|---|
type |
Required. An existing, non-archived event type. |
data |
Required. A JSON object, validated against the type’s current schema. |
customer |
Send only to this customer’s endpoints. Your external_id or a cst_… ID. |
endpoint_id |
Send only to this endpoint (dst_…). It must be active and subscribed to the type. |
idempotency_key |
Up to 200 characters. May also be sent as an Idempotency-Key header. |
Response
202 Accepted once the message and its deliveries are stored:
{
"id": "msg_…",
"event_type": "order.shipped",
"version": 1,
"customer": "acme",
"idempotency_key": "order-1042-shipped",
"delivery_count": 2,
"created": 1767225600000
}
202 means Ensue has the message durably. The deliveries are attempted straight afterwards and retried if they fail, so you never need to retry a send that was accepted. delivery_count is how many endpoints it was queued for; it can be 0 when nothing subscribes.
Who receives it
| You send | Delivered to |
|---|---|
customer only |
That customer’s active endpoints subscribed to the type |
nothing but type |
Every customer’s active endpoints subscribed to the type |
endpoint_id |
Just that one endpoint, which must be subscribed |
Paused endpoints are skipped. Sending to a paused endpoint by ID fails with 409 endpoint_paused, so a targeted send never silently goes nowhere.
What the endpoint receives
The delivered body is an envelope around your data:
{
"id": "msg_…",
"type": "order.shipped",
"version": 1,
"timestamp": "2026-11-10T09:30:00.000Z",
"data": { "order_id": "1042", "carrier": "UPS" }
}
Along with the Standard Webhooks headers webhook-id, webhook-timestamp and webhook-signature. The webhook-id is the message ID and is the same on every retry, so customers can de-duplicate on it.
Idempotency
Network failures happen between your app and Ensue, too. Send an idempotency key that is stable for the thing that happened, such as the order ID plus the event name, so you can retry a send safely.
- The same key with the same request answers
200with the original message and"duplicate": true. Nothing is sent twice. - The same key with a different request answers
409 idempotency_key_reused, so a reused key can never silently swallow a different event. - Two simultaneous sends with one key resolve to one message.
Validation errors
A body that doesn’t match the schema answers 422:
{
"ok": false,
"error": "invalid_data",
"message": "data doesn't match order.shipped v1: Required property 'order_id' not found",
"errors": [{ "path": "/", "message": "Required property 'order_id' not found" }]
}
Nothing is sent and nothing is counted. See Limits and errors for every response.