> ## 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.

# Outbound pause and the resume propagation loop

> How a refused send becomes a resumed send — pre-flight refusals vs gate refusals, the recovery loop per block cause, the single resume path every wallet-funding event runs through, and the polled gate flip.

# Outbound pause and the resume propagation loop

When your wallet can't pay for a send, Orbit refuses it with 402 and tells you
why. This page is the recovery loop: which refusal you get, what to do for each
block cause, and how a credit becomes "sending resumed" without waiting for a
background tick. The flags taxonomy lives on
[the outbound pause gate and free-channel exemption](/concepts/outbound-pause-and-free-channel-exemption);
this page owns the credit-to-resume loop end to end.

## When the wallet blocks a send

Two refusal classes share the 402 status, and `GET /api/v1/billing/balance`
always names the state in `outbound_paused` / `outbound_blocked` and the cause
in `outbound_block_reason`.

* **Pre-flight — `INSUFFICIENT_BALANCE` (402).** The send itself can't be paid
  for at the current balance. No pause flag is required — the wallet simply
  lacks the funds. Top up and resend.
* **Gate — `SENDING_PAUSED` (402).** A soft pause the billing engine set.
  `outbound_paused` is true and `outbound_block_reason` names why:
  `wallet_empty` (auto-pause-on-zero), `billing_alert:<id>:<name>` (a spend or
  balance threshold you configured), or `dunning_failed_3x` (repeated failed
  payments).
* **Gate — `SENDING_BLOCKED` (402).** A hard hold —
  `subscription_suspended`, `payment_dispute_active`, an admin suspension, or
  a `block_outbound` alert action. Nothing self-serves back into sending; the
  hold needs an update to the payment method, a dispute resolution, or support.

The response is authoritative both ways: send-time checks run server-side on
every attempt, so a degraded balance read (`degraded: true` on the endpoint)
can never lift a real pause.

## The recovery loop per cause

Treat all three codes as terminal — never hot-retry a 402.

* **`wallet_empty` → top up.** Any credit path re-arms the gate: card top-up,
  crypto top-up, auto-top-up, a refund credit, or a bonus/adjustment credit
  issued from the Billing console. The gate clears on the credit event itself
  (see the next section); free channels like WhatsApp keep sending even while
  the paid-channel pause persists (the exemption on
  [the pause gate page](/concepts/outbound-pause-and-free-channel-exemption)).
* **`billing_alert:<id>:<name>` → resolve the alert.** Topping up adds balance
  but does not silence the alert. Either trim the offending threshold under
  Dashboard → Billing → Alerts, or have an owner/admin call the
  flags-reset endpoint (`POST /api/v1/billing/alerts/reset-outbound` — the
  dashboard's clear button calls the same route, and it clears both the
  `outbound_paused` and `outbound_blocked` flags the alert set). The flag
  drops as soon as the alert clears.
* **`dunning_failed_3x` → resolve dunning.** Update the payment method; the
  payment-retry resolver clears the dunning hold only after a successful
  charge. A positive balance by itself never clears a dunning hold — the
  resume path acts on `wallet_empty`-marked pauses alone.

## The shared resume propagation block

Every wallet-funding path — card top-up checkout, crypto confirmation,
auto-top-up, refund credits, and operator-issued credits — runs the same
resume routine when it lands a credit. The routine:

1. Clears the `wallet_empty` pause flag with a reason guard — it touches only
   a pause the balance monitor marked `wallet_empty`. A billing-alert hold, a
   dunning hold, a suspension, or any admin set hold is left untouched.
2. Busts the caches that mirror the pause flag — the send-time gate read and
   the balance-banner read — so the next send attempt and the next balance
   poll see the cleared state immediately instead of waiting out short cache
   TTLs.
3. Invalidates the cached balance response so the next
   `GET /api/v1/billing/balance` reflects the fresh ledger.

Because the routine is fail-open, the credit still lands when the flag-clear
errors — the balance-sync sweep (every few minutes) remains the backstop; the
inline clear only closes the stale window from minutes to sub-second. This is
also why an operator-issued bonus or adjustment credit behaves identically to
a paid top-up: every path funnels through the same resume block, so no funding
path can drift into "balance updated, gate still paused."

## Poll until the gate flips

After resolving the cause, poll until `outbound_paused` is false, then resume
sending:

```bash theme={null}
curl -s https://api.orbit.devotel.io/api/v1/billing/balance \
  -H "X-API-Key: $ORBIT_API_KEY"
```

```json Recovering theme={null}
{
  "data": {
    "balance_usd": 150.0,
    "balance_cents": 15000,
    "credits": 15000,
    "outbound_paused": true,
    "outbound_block_reason": "wallet_empty"
  }
}
```

```json Resumed theme={null}
{
  "data": {
    "balance_usd": 150.0,
    "balance_cents": 15000,
    "credits": 15000,
    "outbound_paused": false,
    "outbound_block_reason": null
  }
}
```

Poll on a moderate cadence (every few seconds) rather than hot-looping, and
see [send gating](/concepts/send-gating-and-quiet-hours) for the full
recovery-style matrix. For hard blocks, `outbound_blocked` follows the same
poll loop but the cause resolves in the dashboard or with support, not via a
funding endpoint.

## Why funding retry is safe

Resuming often means retrying a funding call that timed out mid-response. The
top-up endpoints are idempotent per organization and event: the request's
idempotency key names the checkout session or payment reference, the result
caches for 24 hours, and a retry replays the cached credit instead of moving
money twice. The same idempotency contract covers the usage-debit side —
inbound retried sends can't double-charge the wallet either (ledger mechanics
on
[wallets, credits, and charges](/concepts/wallets-credits-and-charges)). So
"retry the top-up, then re-poll the balance" is always safe.

## Related pages

* [The outbound pause gate and free-channel exemption](/concepts/outbound-pause-and-free-channel-exemption) —
  which hold classes exist and which channels they exempt.
* [The billing gate chain](/concepts/billing-gate-chain-model) — the ordered
  pre-flight → flags → fund-path → decrement chain every send walks.
* [Billing and wallet](/concepts/billing-and-wallet) — rating, FX,
  and the ledger.
* [Billing API reference](/api-reference/billing) — balance, top-up, and
  alert endpoints per operation.
