Appearance
Events
Send your own server-side events to Zay in batches — attribution or product events your backend observes. This is the inbound counterpart to webhooks: there Zay sends events to you; here you send events to Zay.
To receive events from Zay instead, see Webhook endpoints and the Event catalog.
| Endpoint | Operation |
|---|---|
POST /merchants/v1/events | Submit events |
Submit events
Submit a batch of up to 1,000 events in one request. The batch is accepted for asynchronous processing — a 202 means it was queued, not that every event has been processed. Validation is all-or-nothing: if any event is malformed, the whole batch is rejected and nothing is queued.
POST /merchants/v1/events
Request body
| Field | Type | Description |
|---|---|---|
eventsrequired | array of object |
Each item of events:
| Field | Type | Description |
|---|---|---|
event_name | string | Identifier for the event type. Case-insensitive. |
payload | object | Custom JSON object containing event-specific properties. |
event_datetime | string (date-time) | When the event occurred, ISO 8601. |
event_id | string (uuid) | UUIDv4 uniquely identifying this event. Enables idempotent delivery. |
user_external_id | string | The merchant's own id for the user the event is about (the external_id you set when creating the user). Valid before and after the user exists in Zay, so a whole journey shares one id. |
device_id | string | Optional. Your own client/device identifier for the event, if you have one. Forwarded to Amplitude as the event's device id. |
user_external_id is your own id for the user — the external_id you set with Create user. Because it is yours, you can send events before the user exists in Zay; events with the same user_external_id from before and after signup assemble into one journey.
Idempotency and limits
- Per-event dedup.
event_iddeduplicates individual events: re-submitting an event whoseevent_idZay has seen in the last 24 hours is a no-op, so retrying a whole batch never double-counts. Use a fresh UUIDv4 per logical event. - Batch size. Up to 1,000 events per request, and the request body must stay under 1 MB. Exceeding either limit returns
413. - A request-level
Idempotency-Keyheader (see Idempotency) is also honored, but per-eventevent_idis the primary safeguard against double-counting on retries.
Returns 202 Accepted with no body. A batch either validates and is queued in full, or is rejected whole.
Errors:
400— malformed JSON, or an event failed validation (missing or blankevent_name,payload,event_datetime,event_idoruser_external_id; malformedevent_idUUID; unparseableevent_datetime).401— invalid signature.413— more than 1,000 events, or request body over 1 MB.429— rate limit exceeded.
Example
bash
curl -X POST "https://api-connect.zay.me/merchants/v1/events" \
-H "Content-Type: application/json" \
-H "zay-api-key: $ZAY_API_KEY" \
-H "zay-timestamp: $TS" \
-H "zay-signature: $SIG" \
-H 'Idempotency-Key: "b3c1e0a2-8f4d-4a1e-9c2b-1f6a2d5e7c90"' \
-d '{
"events": [
{
"event_name": "signup_completed",
"payload": {"plan": "pro", "referrer": "campaign-42"},
"event_datetime": "2025-12-05T12:05:49Z",
"event_id": "0192f5b0-1234-7e8d-89ab-cdef01234567",
"user_external_id": "acme-user-42"
}
]
}'