API and delivery

Receive delivery receipts

The platform POSTs to a URL you configure, with a token you generate. Two implementation details decide whether you lose events.

5 min read · updated 2026-10-13

How it is set up

Configure the callback URL and generate the callback token in the console, then expose an endpoint that accepts a JSON POST. The platform posts when a message reaches a terminal state.

Each request carries an X-Callback-Token header. Verify it server-side before trusting the body.

  1. Set the callback URL

    Console → Settings → Webhook. Use an HTTPS endpoint that is reachable from the public internet.

  2. Generate the webhook token

    The token is what proves a request came from the platform. Store it server-side, not in client code.

  3. Expose the endpoint

    Accept a JSON POST, verify the header, then acknowledge with a 2xx response.

What arrives

FieldMeaning
messageIdPlatform message ID — your de-duplication key
statusdelivered or failed, and nothing else
providerMessageIdProvider-side ID
rawStatusThe provider's own wording, e.g. Twilio delivered or Vonage expired
to / providerRecipient and the provider that carried it
errorCodeReason, on failure or refusal
encoding / segmentsEncoding used and billed segments
timestampWhen the platform pushed it, ISO-8601 UTC

Retries: return 2xx, and de-duplicate anyway

A non-2xx response, or a timeout, is retried on a 1s / 5s / 15s backoff, three times. After that the platform gives up and records the delivery as failed.

That retry behaviour means you can legitimately receive the same event twice. De-duplicate on messageId rather than assuming exactly-once delivery.

  • Return 2xx only after you have durably accepted the event, not before.
  • De-duplicate on messageId.
  • Do not do slow work inline — a callback endpoint that takes seconds is a callback endpoint that gets retried.

Which messages you will not hear about

Suppressed messages produce no callback. They were never handed to a provider, so delivered and failed do not apply — the outcome was fixed at acceptance.

Keep reading

Create, bind and rotate API keys

A key proves which tenant is calling and which channels it may use. It is shown in full once, and a key with no binding cannot send at all.

Read this article →

Send a message with the API

One endpoint accepts asynchronously. A success code means the platform took the message — not that a handset received it.

Read this article →

What each message status means

Four states, and one of them does not belong in the same bucket as the others. Reading suppressed as a failure sends you looking in the wrong place.

Read this article →