Skip to content

Webhooks & Delivery Reports ​

A successful send means "accepted for delivery", not "delivered". Delivery reports (DRs) arrive asynchronously as webhooks keyed by the transaction_uuid you set on the message.

Receive a delivery report ​

Point a public HTTPS endpoint at MessageEagle and handle the callback:

ts
app.post("/webhooks/messageeagle", (req, res) => {
  const { transaction_uuid, status } = req.body;
  // 1. Acknowledge fast — return 2xx before doing slow work.
  res.sendStatus(200);
  // 2. Look up the original message by transaction_uuid and update its status.
  queue.enqueue({ transaction_uuid, status });
});

Build for the hard case ​

Webhooks are at-least-once. Design every handler accordingly.

  • Idempotent updates. Key on transaction_uuid; applying the same DR twice must be a no-op. Prefer an UPSERT over an INSERT.
  • Acknowledge first, process later. Return 2xx immediately, then do the real work on a queue. Slow handlers cause redeliveries.
  • Tolerate out-of-order. A delivered can arrive before a sent. Use a status precedence, not last-write-wins.

Verify the source

Validate the request signature (or a shared secret) before trusting a payload. Never act on a webhook body you can't authenticate.

Status model ​

StatusMeaning
queuedAccepted, awaiting dispatch.
sentHanded to the carrier.
deliveredConfirmed on the handset.
failedCarrier rejected or could not deliver.
expiredTTL elapsed before delivery (e.g. unreachable handset).

Voice completion ​

Voice sessions emit completion callbacks too — recordings, transcripts, DTMF logs, and cost land on the VoiceSession. Poll GET /organization/{organizationId}/webhook-deliveries as a fallback if a callback is missed — see Webhook Deliveries.