Skip to main content
Trackly SMS sends webhook events to notify you of message delivery updates, inbound replies, and opt-out changes. Events are delivered to your configured webhook URLs via HTTP POST.
Webhooks are configured per sending list in the dashboard under your list’s Delivery Forwarding settings. Each webhook subscribes to one or more event types, and you can send a test event from the dashboard to verify your endpoint.

Event Types

Request Format

Events are batched: each POST contains an events array with one or more events that occurred in the same processing cycle. Cycles run every few seconds, so events from the same short window arrive together in one POST (see Delivery Semantics). Each event has a type, an ISO-8601 timestamp, and a data object whose fields depend on the event type.

Delivery Event

Sent when a delivery status update is received for a message you sent.
Not every route currently emits delivery events. Lists on routes without delivery-event support emit reply and unsubscribe events only.

Delivery Statuses

delivered is the success terminal state. The exact vocabulary varies by carrier route — some routes pass the carrier’s own status through verbatim, so you may also see intermediate values (e.g. sent, accepted). Treat any value other than delivered as non-success, and any value you don’t recognize as non-terminal.

Reply Event

Sent when a contact sends an inbound SMS to your list number. Every inbound message emits a reply event — including opt-out keywords. When a message is an opt-out, an unsubscribe event is emitted in addition to the reply, so a contact who texts STOP produces both a reply and an unsubscribe (typically in the same batch). To act on opt-outs, key off the unsubscribe event — do not assume a reply means the contact stayed subscribed. Replies are also stored and viewable in the dashboard under Messages > Replies. Like every event, it arrives inside the events array (see Request Format).
message_id is an opaque identifier — do not assume a fixed length or format. Store them as variable-length strings.
from is your sending list number; to is the contact who replied; text is their message body.

Unsubscribe Event

Sent when a contact is opted out — an opt-out keyword reply, a carrier spam complaint, or repeated hard delivery failures. The opt-out matcher is intentionally broad: it recognizes STOP, STOPALL, UNSUBSCRIBE, QUIT, CANCEL, END, REMOVE, OPTOUT and many common variants and phrasings (e.g. “stop texting”, “take me off the list”, “no more texts”), plus spam-complaint and abuse language — treat these as examples, not an exhaustive list. Like every event, it arrives inside the events array (see Request Format).
The contact is immediately marked as unsubscribed (active: false) on the corresponding list. Future sends are blocked automatically. See Compliance for the auto-removal rules.
Re-subscription does not emit a dedicated event. When a previously opted-out contact opts back in (an opt-in keyword such as START, UNSTOP, SUBSCRIBE, OPTIN), they are re-subscribed and sending resumes — but there is no resubscribe webhook event. The only signal you receive is the ordinary reply event carrying their inbound text (e.g. "Start"). If you mirror subscription state from webhooks, detect opt-ins from the reply body — do not expect a counterpart to the unsubscribe event.

Delivery Semantics

  • Batching cadence: events are collected and flushed on a short polling cycle — roughly every 5 seconds — so you normally receive an event within seconds of the underlying status change. This is best-effort, not a guaranteed interval: a quiet window produces no POST, and a burst is grouped into a single POST (tens of events).
  • Timeout: your endpoint must respond within 10 seconds. Return a 2xx status quickly and process events asynchronously.
  • No retries: event delivery is fire-and-forget. A non-2xx response or timeout is logged but not retried.
  • At-least-once, and statuses can be revised: carrier receipts can be redelivered upstream, and a later receipt can revise a message’s status (e.g. delivered corrected to failed). message_id identifies the original send — not a unique event. To drop true duplicates, dedupe on message_id + status (or provider_message_id + status) and let the latest received status win.
  • Authentication: if your webhook has a secret configured, every request includes it in the X-Webhook-Secret header — compare it against your stored value before trusting the payload.

Next Steps

Webhooks Integration

Configure webhook endpoints

Send Message

Send a message to trigger events