> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting: message stuck in queued

> Work through why a message is holding at queued instead of sending — from scheduled send times and quiet-hours holds to compliance gates, sender-pool exhaustion, and provider connectivity.

# Troubleshooting: message stuck in queued

A message that stays at `queued` has not been sent to a provider yet — it is
sitting in the pre-delivery stage. This page walks you through what each
status means, the causes that park a message at `queued`, and how to unstick
it without making the problem worse.

Distinguish two failure shapes before you start: a row at `queued` has
**never left Orbit** — the hold is on your side of the provider handoff, and
this page is the diagnostic. A row at `submitted_no_receipt` has **already
left Orbit** and is waiting on a carrier delivery receipt — that is the
post-queue stage, covered by the
[message sent but no delivery receipt](/troubleshooting/submitted-no-receipt)
page.

## How message statuses fit together

Every message moves through a defined set of statuses, and each transition is
gated — a message cannot jump from `queued` straight to `delivered`, and a
terminal status like `read` or `failed` cannot move backward. The happy path
for an immediate send is:

```text theme={null}
pending → queued → sending → sent → delivered → read
```

For a scheduled send, the message sits at `scheduled` until its `send_at`
time arrives, then joins the queue:

```text theme={null}
pending → scheduled → queued → sending → sent → delivered → read
```

Statuses like `accepted` (the synchronous pre-queue handoff), `test_sent`
(sandbox mode), and `cancelled` (a scheduled message you cancelled before it
sent) exist alongside the main path. Status updates are ordered, so each row
can only move forward along an allowed transition — a stale carrier callback
cannot drag a settled message back to `queued`.

## Where to check the status

* **Delivery Log**: open **Messages → Tools → Delivery log** and search the
  message ID (`msg_…`), the provider reference, or the recipient. Filter by
  the **Status** filter to isolate stuck rows — for example
  `/messages/delivery-log?status=queued&direction=outbound` shows every
  queued outbound message. See the [Delivery Log guide](/guides/delivery-log).
* **Per-channel workspace**: SMS, WhatsApp, and Email channels each show
  outbound history with the same status values.
* **API**: call `GET /api/v1/messages` with a `status=queued` filter, or
  fetch the row by ID. The `status` field tells you where the row is; the
  response also tells you whether the row carries a `send_at` (scheduled),
  or a provider reference once it reaches `sent`.

## Common causes and how to unstick them

Work through these in order — they cover the overwhelming majority of
queued-for-longer-than-expected rows.

| Cause                                   | How to confirm                                                                                                                                                                                                                     | What to do                                                                                                                                                                                                                                                                                                 |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Scheduled `send_at` not reached yet** | The message shows `scheduled` in the Delivery Log before queue time; `send_at` in the response is in the future                                                                                                                    | This is expected behaviour — the message will move to `queued` then `sending` at the scheduled time. Cancel it with `POST /api/v1/messages/:id/cancel` if you no longer want it                                                                                                                            |
| **Frequency cap holding the campaign**  | The message belongs to a campaign configured with per-recipient or per-window frequency caps; the recipient has a recent send                                                                                                      | The send resumes automatically when the cap window resets. Throttle the campaign send rate or widen the cap if you need it out now                                                                                                                                                                         |
| **Quiet-hours hold**                    | Your organization's compliance settings enforce a quiet-hours window (a tenant-controlled toggle); current local time for the recipient falls inside it                                                                            | The message sends when the window reopens. Change your quiet-hours window if the hold is wrong                                                                                                                                                                                                             |
| **Compliance-profile gate**             | A strict-market sender profile (for example an unregistered sender ID, a 10DLC campaign pending approval, or a WhatsApp template not yet approved) is blocking outbound sends                                                      | Complete the registration or approval step against the sender pool, then re-send. The hold lifts once the gate clears                                                                                                                                                                                      |
| **IP warm-up hold** (email only)        | The send is on a warming IP or fresh sender reputation and the day's warm-up volume cap is already spent — `GET /api/v1/email/warmup-enforcement` returns a `partial` or `block` decision, and the excess stays queued server-side | This is a deliberate reputation gate, not an error — the queue drains as the daily cap resets (the `retryAfter` field) and lifts entirely once the ramp finishes. Check position with `GET /api/v1/email/warmup-status`; see the [Email API warm-up endpoints](/api-reference/email) for the full contract |
| **Exhausted sender pool**               | Every sender in the pool used for this message is over its throughput limit or removed                                                                                                                                             | Add senders to the pool or route the message through a pool with free capacity. The queued row sends as soon as a sender is available                                                                                                                                                                      |
| **Provider-side connectivity**          | Multiple messages across multiple recipients are all stuck at `queued` at the same time — not a single recipient                                                                                                                   | Check the status page and your provider webhook endpoint health; the queue drains when connectivity returns                                                                                                                                                                                                |

<Note>
  A message that never gets a delivery receipt moves to
  `submitted_no_receipt` — that means it left the queue. A row still at
  `queued` has never left the queue, which is exactly the state this page
  diagnoses.
</Note>

## Diagnosis checklist

1. **Get the message ID.** Open the Delivery Log or your channel workspace
   and copy the `msg_…` ID from the row.
2. **Read the message detail.** Open the full message detail page — it
   shows the send channel, the sender pool, the scheduled time if one
   exists, and the campaign it belongs to. Each of those fields maps to a
   row in the cause table above.
3. **Check the campaign.** If the message came from a campaign, open that
   campaign's settings: frequency caps, quiet hours, and sender pool are
   configured there.
4. **Check tenant-level compliance settings.** Quiet-hours and
   sender-registration gates are organization-wide. Confirm the hold is
   intentional before you clear it.
5. **Query the API if the dashboard shows conflicting data.**
   `GET /api/v1/messages/:id` returns the authoritative `status`, `send_at`,
   `channel`, and any provider reference.

## What not to do

Do not spam `POST /api/v1/messages/:id/retry` while the cause is unknown. A
retry against a quiet-hours hold, a pending sender approval, or a capped growth
window just moves the same blocked message through the same gate again. Fix the
cause first, then retry.

Also avoid re-sending a fresh copy of the message to an end user while the
original row is still queued — once the hold clears, both copies go out, and
your recipient receives the same content twice.

## When to escalate

If you worked through the checklist, the cause is not a hold you control, and
messages are still stuck for more than a few minutes, open a support ticket
and include both of these so we can trace the row without a back-and-forth:

* Your **tenant ID** (shown in the dashboard under Settings → Organization,
  and returned by the `GET /api/v1/me` response as `organizationId`).
* The **message ID** of one stuck row (`msg_…`).

For a stuck **email** send, also include your warm-up position — the
`currentDay` and `todayCap` values from `GET /api/v1/email/warmup-status` —
so support can tell a deliberate ramp hold from a real fault on the first
reply.

That pair lets support pull the exact queue entry and the exact send-gate
evaluation without you having to re-describe the symptom.

## Status decoder

Every status value the Delivery Log filter and the `GET /api/v1/messages`
response can return, and what it means for diagnosis:

| Status                 | Meaning                                                       | Diagnosis hint                                                                                                                                                                     |
| ---------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pending`              | Row created; not yet handed to the queue                      | Transient; normal for less than a second                                                                                                                                           |
| `scheduled`            | Waiting for the `send_at` time                                | Expected; not a failure until `send_at` passes and it still hasn't moved                                                                                                           |
| `queued`               | In the dispatch queue, not yet handed to a sender or provider | Work through the cause table above                                                                                                                                                 |
| `accepted`             | Handed to the send pipeline pre-dispatch                      | Transient                                                                                                                                                                          |
| `sending`              | Dispatch in progress to the provider                          | Transient; provider call in flight                                                                                                                                                 |
| `sent`                 | Provider accepted the message                                 | Waiting on a carrier DLR; see undelivered/failed if it later flips                                                                                                                 |
| `submitted_no_receipt` | No delivery receipt yet, but sent                             | Provider-side; the row can still advance to `delivered` when a late DLR lands — see [Troubleshooting: message sent but no delivery receipt](/troubleshooting/submitted-no-receipt) |
| `delivered`            | Carrier confirmed delivery to the recipient                   | Final outcome reached                                                                                                                                                              |
| `read`                 | Recipient opened/read (channels that report read receipts)    | Final outcome reached                                                                                                                                                              |
| `undelivered`          | Carrier tried and failed to reach the recipient               | Check the destination address / handset                                                                                                                                            |
| `rejected`             | Provider refused the send outright                            | Check message-content violation or sender-registration status                                                                                                                      |
| `failed`               | Send path errored before reaching the provider                | Retry after checking the cause table                                                                                                                                               |
| `expired`              | Time-to-live exceeded before send                             | Resend with a longer window or fix the hold that stalled it                                                                                                                        |
| `cancelled`            | You cancelled the scheduled message before it sent            | Final outcome reached                                                                                                                                                              |
| `test_sent`            | Sent in sandbox mode — no real provider call                  | Expected in sandbox                                                                                                                                                                |
| `deleted`              | Soft-deleted by an operator                                   | Final outcome reached                                                                                                                                                              |

If a row is sitting on any of the blocked-in-queue statuses (`queued`,
`scheduled`, `pending`, `accepted`, `sending`) for longer than you expect,
the cause table and checklist above will get you to the hold faster than a
blind retry.
