Outpost logoOutpost Docs

Events

The immutable audit trail for message lifecycle and phone state changes.

Events are immutable audit log entries. They capture what happened, when, and why - for every message lifecycle change and every phone state change - enabling debugging, analytics, and compliance reporting.

In the dashboard: a phone number's page shows its full event trail, see Phones & the Number Pool.

How they relate

Events come in two categories:

  • MESSAGE events attach to a message and track its lifecycle from queuing through settlement.
  • PHONE events attach to a phone. Crucially, they exist so that rejections are auditable even when no message was ever created - a duplicate, invalid number, or opted-out rejection happens before message creation, and the phone record is where that history lives.

Events are also the source for webhook fan-out: delivery attempts are recorded on the event itself, making each event the complete audit trail of both what happened and who was notified.

What fires when

During a send, events land in two places depending on how far the item got:

StageOutcomeEventAttached to
API validationDuplicate for a communicationDUPLICATEPhone
API validationNumber invalid (landline, ...)INVALID_NUMBERPhone
API validationPhone opted outNO_SEND_OPT_OUTPhone
API acceptMessage queuedQUEUEDMessage
Send workerAWS acceptedPROVIDER_ACCEPTEDMessage
Send workerAWS rejected, retries leftPROVIDER_FAILEDMessage
Send workerAWS rejected, not retryable or attempts exhaustedFAILED plus PROVIDER_FAILED or MAX_ATTEMPTS_REACHEDMessage
Send workerPreflight failure (permanent)FAILED plus one of PHONE_NOT_FOUND, NO_SEND_OPT_OUT, MAX_ATTEMPTS_REACHEDMessage
Send workerDuplicate send dropped (attempt in flight)ACTIVE_ATTEMPTS (not terminal, no settle)Message
Delivery receiptNon-failure receipt, final or interimDELIVERED, BLOCKED, CARRIER_ROUTING, SENTMessage
Delivery receiptFinal failure, retries leftATTEMPT_FAILED (message requeues, not terminal)Message
Delivery receiptFinal failure, attempts exhaustedFAILED plus MAX_ATTEMPTS_REACHED (settles)Message
Opt-out / opt-inAny channelOPTED_OUT / OPTED_INPhone

FAILED is always terminal and fires exactly once per message, alongside the specific reason event that explains why. ATTEMPT_FAILED means a single delivery attempt failed but the message still has attempts remaining - it is not terminal.

Each event stores its category, type, the raw provider payload where applicable, and the time it occurred.

Key properties

Immutable. Events are never updated or deleted (webhook delivery status, recorded on the event, is the one addition made after creation).

Non-blocking. Event creation never fails the operation that triggered it - a hiccup writing an audit record won't stop a message from sending.

Queryable per entity. GET /messages/:messageId/events and GET /phones/:phone/events return the history for one message or one phone.

API reference

Calling from TypeScript? See Generating a Typed Client.

On this page