Skip to content

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.

EndpointOperation
POST /merchants/v1/eventsSubmit 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

FieldTypeDescription
eventsrequiredarray of object

Each item of events:

FieldTypeDescription
event_namestringIdentifier for the event type. Case-insensitive.
payloadobjectCustom JSON object containing event-specific properties.
event_datetimestring (date-time)When the event occurred, ISO 8601.
event_idstring (uuid)UUIDv4 uniquely identifying this event. Enables idempotent delivery.
user_external_idstringThe 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_idstringOptional. 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_id deduplicates individual events: re-submitting an event whose event_id Zay 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-Key header (see Idempotency) is also honored, but per-event event_id is 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 blank event_name, payload, event_datetime, event_id or user_external_id; malformed event_id UUID; unparseable event_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"
      }
    ]
  }'