Skip to content

Send product events ​

Send Zay the events your backend sees — signups, purchases, campaign touches — so they join the user's Zay journey in analytics.

This is optional. You don't need it to onboard or pay users.

Requirements ​

RequirementDescription
Signed requestsWorking signing code — see Authentication
Your own user idsThe id you set as external_id with Create user

How it works ​

  1. Use the same user id everywhere
  2. Batch your events
  3. Send the batch
  4. Retry without double-counting

1. Use the same user id everywhere ​

Events are tied to users by your id, user_external_id. Set the same value as external_id when you create the user, and events from before and after signup join into one journey:

json
{ "phone_number": "+15555550100", "external_id": "acme-user-42" }

Because the id is yours, you can send events for a user before they exist in Zay.

2. Batch your events ​

Collect events and send them together — up to 1,000 per request, under 1 MB. Each event needs:

FieldWhat to put in it
event_nameWhat happened, e.g. signup_completed. Case-insensitive
payloadAny JSON object of properties
event_datetimeWhen it happened on your side, ISO 8601, UTC
event_idA new UUIDv4 for this event — generate it once, when the event happens
user_external_idYour id for the user
device_idOptional — your client or device id, if you have one

The full schema is in Submit events.

3. Send the batch ​

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" \
  -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"
      }
    ]
  }'

You get 202 Accepted with no body: the batch is queued. If any event is invalid, the whole batch is rejected with 400 and nothing is queued — fix it and send it again.

4. Retry without double-counting ​

If a batch fails with a timeout or a 5xx, send the same events again with the same event_ids. Zay ignores any event_id it has seen in the last 24 hours, so a retried batch never counts an event twice. Don't regenerate event_id on retry.