Documentation
Sign inGet started

SMS events reference

Every message moves through a lifecycle, and Bird emits an event at each step. This page is the full event vocabulary; how events are delivered to your endpoint — signatures, retries, replay — is covered in the Webhooks guide.
The delivery lifecycle, as a path through the event types:
  • sms.accepted — Bird has the message and is preparing to hand it to a carrier
  • sms.sent — the message was handed to the carrier; awaiting a delivery receipt
  • sms.delivered — the carrier confirmed delivery to the handset
  • → or sms.undelivered — a non-permanent non-delivery (handset off, unreachable, content blocked)
  • → or sms.failed — a permanent failure; the message will not be delivered
  • → or sms.rejected — Bird refused the message before it reached a carrier
  • → or sms.expired — the message's validity window elapsed before a terminal receipt arrived
Each message ends in exactly one terminal status — delivered, undelivered, failed, rejected, or expired. Inbound messages surface through sms.received instead of this outbound path.
The event type is an open enum: Bird may add new event types over time, so treat an unrecognized type as a future event rather than an error. Match the types you handle and ignore the rest.

The event envelope

Events arrive at your webhook endpoint in the Standard Webhooks nested envelope described in the Webhooks guide — three fields: type, timestamp, and a type-specific data object. The event's identity is not in the body: it rides in the webhook-id HTTP header, which is stable across retries of the same delivery and is your deduplication key.
FieldDescription
typeOne of the event types on this page, e.g. sms.delivered
timestampWhen the event occurred (RFC 3339) — sort by this, never by arrival order, since deliveries are not ordered
dataEvent-specific payload (fields below)
Every SMS event's data carries the identity base: sms_id, workspace_id, the to and from addresses, and the tags and metadata you set on the send — echoed on every event so you can route and correlate against your own records without an extra lookup (each is null when the send carried none).
Ejemplo de código
{
  "type": "sms.delivered",
  "timestamp": "2026-06-10T14:30:00Z",
  "data": {
    "sms_id": "sms_01krdgeqcxet5s7t44vh8rt9mg",
    "workspace_id": "ws_01krdgeqcxet5s7t44vh8rt9mg",
    "to": "+15551234567",
    "from": "Bird",
    "carrier": "Example Wireless",
    "mcc_mnc": "310260",
    "tags": [{ "name": "campaign", "value": "spring-2026" }],
    "metadata": { "order_id": "ord_123" }
  }
}

Lifecycle events

sms.accepted

Fires when Bird accepts the send and begins preparing to hand it to a carrier. This is the first event in every outbound message's stream. Payload: the identity base only.

sms.sent

Fires when Bird has handed the message to the carrier and is awaiting a delivery receipt. Payload: the identity base only — to measure processing latency, compare this event's timestamp with sms.accepted's.

sms.delivered

The carrier confirmed the message reached the handset. Payload adds carrier and mcc_mnc — the delivering network and its mobile country/network code.

Failure events

sms.undelivered

A non-permanent non-delivery — the handset was off or unreachable, or the carrier blocked the content. Payload adds an error object with the reason.

sms.failed

A permanent delivery failure; the message will not be delivered. Payload adds an error object with the reason.

sms.rejected

Bird refused the message before it ever reached a carrier — a validation or policy rejection, so no delivery was attempted. This is distinct from a failure at the carrier: a rejection is the message never getting that far. Payload adds an error object with the reason.

sms.expired

The message's validity window elapsed before a terminal delivery receipt arrived. Payload: the identity base only.

The events API

The same per-message events are queryable after the fact with GET /v1/sms/messages/{message_id}/events. It returns the message's events in chronological order, in full — the timeline is bounded, so it is not paginated. Each event carries:
FieldDescription
idThe event ID (evt_ prefix)
typeThe event type, one of those above
occurred_atWhen the event occurred (RFC 3339)
carrierThe delivering carrier, when known (present on delivery events)
mcc_mncThe mobile country/network code, when known
errorThe failure detail (description and code), present on undelivered, failed, and rejected events
Use the events API to backfill, replay, or reconcile against your webhook deliveries by sms_id. It's the same stream the SMS log's per-message timeline is rendered from.

Next steps

  • Webhooks & events — endpoint setup, signature verification, retries, and replay
  • SMS log — the per-message timeline these events drive
  • Sending SMS — the send payload whose tags and metadata echo on every event