Skip to main content

Trace a message through Delivery Logs

The Developer → Delivery Logs page in the dashboard is the console-first way to answer “what happened to this message?” — without writing an API call or waiting on a support response. It searches every outbound and inbound message across channels, then opens one message’s lifecycle so you can read it step by step. Use it alongside the Request Logs (HTTP ingress) — delivery logs cover the downstream message lifecycle; request logs cover the HTTP shape of your API traffic. The page and its drill-down require an owner, admin, or developer role on your dashboard session — the recipient numbers and message body fragments in the rows are the same PII tier as API keys and webhooks.

What the page shows

Every row is one message — inbound or outbound, on any channel — with its channel, direction, recipient, sender, current status, and timestamp. A message moves through the lifecycle as:
  1. Accepted — Orbit received your send request and queued the message.
  2. Routed — a route and carrier were selected for the recipient.
  3. Submitted — the message was handed to the carrier or provider.
  4. Terminaldelivered, read, failed, rejected, or submitted with no receipt after the window closes.
The status filter narrows the list to one terminal state (queued, sent, delivered, read, failed, or rejected), and the channel and direction filters narrow it further. The free-text box matches recipients, senders, and body fragments — or paste a full msg_… id to jump straight to that one delivery.

When to use it

  • “A message didn’t arrive.” Filter to the recipient, read the terminal status, then drill into the steps to see where the lifecycle stopped.
  • “The DLR says submitted, no receipt.” The terminal step names the carrier-rejection reason when the carrier returned one — start there before touching your code.
  • “Did the WhatsApp send after the SMS failed?” One cross-channel list instead of four channel tabs — filter by the recipient and compare rows.
For the same lookups over the API (a support script, an on-call runbook), the page’s queries map one-to-one onto GET /api/v1/messages — see the Delivery log API guide.

Open a failing message

  1. Open Developer → Delivery Logs in the dashboard.
  2. Paste the message id into the search box. Paste it however you have it — the msg_… id the send API returned, or the id shown on a message page. A fully-typed id resolves to a direct lookup: one row, regardless of the date filter.
  3. Or, with no id in hand, narrow the list — pick a channel and a status (say, failed), set the date range, and click the row for the failing message.
Rows rendered from a direct id lookup carry a Message id match strip above the results. Widen or clear the filters afterward to pivot to related deliveries — the id lookup freezes the list while it’s active so the row you’re on is exactly the id you pasted.

Drill into the steps

Click a row. The detail drawer opens the same per-message surface every channel workspace uses — a status timeline of the lifecycle steps in order, each with its timestamp, and the carrier or provider rejection reason whenever the terminal step carries one:
  • A submitted-no-receipt SMS shows the lifecycle up to the carrier-submission step, with the carrier-side reason (an unreachable handset, a routing refusal) on the failed step when the carrier returned one.
  • A rejected WhatsApp template send ends at the rejection step, with Meta’s template-rejection reason inline — fix the template, then retry.
The drawer also shows the error code and error message fields that travel with the row, and a copy button on the message id — drop the id into a support ticket and whoever picks it up can retrace the same lifecycle.

Share a pre-filtered view

The page reads its initial filters from the URL, so a bookmarks bar, a runbook, or a chat message can carry a ready-made view:
Supported parameters: q (free text or a msg_… id), channel, status (queued, sent, delivered, read, failed, rejected), and direction (outbound, inbound). Values outside those sets are ignored rather than applied, so a hand-built URL cannot seed the page into a state its own filters cannot represent. The same maps one-to-one onto the GET /api/v1/messages filter vocabulary — a link built against the API works in the page and vice versa.

Request Logs vs Delivery Logs

The two developer debugging surfaces answer different questions: A 202 Accepted in Request Logs with no delivery in Delivery Logs means the API took the send but the lifecycle stopped downstream — routing, carrier submission, or the carrier itself. A 4xx in Request Logs means the request never became a message at all, and Delivery Logs has nothing to show for it.

When a log looks incomplete

Two cases to recognize:
  • The lifecycle is still running. A message within its delivery window can sit in a non-terminal status (queued, sent) until the carrier responds or the window closes. The page’s timestamp filters snapshot the moment — a refresh is the update.
  • You built against an hourly-aggregated surface. The analytics-style usage surfaces roll up by the hour and buffer the most recent window. The per-message reads on this page and on GET /api/v1/messages are immediate — when the aggregate looks stale, read the individual delivery rather than waiting for the aggregation to catch up.

Examples

SMS shows submitted but never delivered. Open Developer → Delivery Logs, paste the msg_… id into the search, click the row, and read the steps in the drawer. The submitted-no-receipt lifecycle ends at the carrier-submission step; if the carrier reported a reason, the failed step carries it. Take that reason into troubleshooting “submitted, no receipt” — the page branches by carrier-side cause. WhatsApp template send rejected at send time. Filter to channel whatsapp + status rejected, click the row, and read the Meta rejection reason off the terminal step. Fix the template or the variable shape, then resend from your normal send path — the row’s lifecycle tells you why, not retrying it tells you when.

Frequently asked questions

Why does my pasted id show one row even though the date filter should exclude it?

A fully-typed msg_… id resolves as a direct by-id lookup, which intentionally ignores the date range and channel filters — the promise of the paste target is “jump straight to that delivery,” and a default 30-day window would break it for older messages. Clear the search to return to the filtered list.

The status filter shows rejected but my row says failed — which is it?

Both are terminal, but they differ in intent. rejected means the carrier or provider refused the message outright (a template rejection, a routing refusal); failed means the message was accepted for transport and the delivery then failed. The drill-in drawer’s terminal step carries the reason either way.

Can viewers or billing roles open this page?

No. The rows contain recipient numbers, message body fragments, and per-channel error detail — the same PII tier as API keys and webhooks, so the page is gated to owner, admin, and developer roles.

See also