> ## 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: billing-gate outbound blocks

> Every hard outbound stop your wallet layer can throw that goes beyond the 402 insufficient-balance check — tenant-configured pause/block-flags, billing-provider faults, voice hold faults, and trial-credit gates — and the recovery path for each.

# Troubleshooting: billing-gate outbound blocks

`INSUFFICIENT_BALANCE` (402) is only one stop in the billing gate. A handful
of other codes intercept outbound traffic for reasons the wallet balance
page cannot explain — a customer-configured billing alert, a payment-provider
fault, a voice hold that failed closed, or a trial-credit gate. This page maps
each code to its cause and its recovery.

<Note>
  If your outbound messages return `402 INSUFFICIENT_BALANCE`, work the
  [insufficient-balance page](/troubleshooting/insufficient-balance) instead —
  this page covers every stop *beyond* that one.
</Note>

## 1. Trigger map — customer-configured billing alerts

Billing alerts you config in the dashboard (**Billing → Alerts**, or via
`POST /api/v1/billing/alerts`) watch a spend or balance threshold. When an
alert fires, its `action_on_hit` decides whether outbound stops:

* `pause_outbound` → every send request returns `402 SENDING_PAUSED` until
  reset.
* `block_outbound` → every send request returns `402 SENDING_BLOCKED` until
  reset.
* `notify` → no gate; you get email/SMS and outbound keeps flowing.

The rejection is stable across surfaces: the messaging send path
(`POST /messages`), every voice origination path (Jambonz UA, click-to-call,
conference adds), and number purchases all throw the same code with the same
reason in the payload.

Diagnose the cause from the response itself. The body returns `details.reason`:

| `details.reason`                                           | What set it                                                                | How to recover                                         |
| ---------------------------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------ |
| `billing_alert:<alert-id>:<name>`                          | One of your billing alerts fired with `pause_outbound` or `block_outbound` | Review in Billing → Alerts and reset (section 2)       |
| `wallet_empty`                                             | Auto-pause-on-zero (wallet empty)                                          | Top up; auto-resumes when the balance reads above zero |
| `dunning` / `dunning_failed_3x`                            | Failed payment retries against your card                                   | Update the payment method in Billing                   |
| `subscription_suspended` / `parent_subscription_suspended` | An upstream org or your own org was suspended                              | Contact your account owner or Devotel support          |
| `payment_dispute_active`                                   | A payment dispute is being resolved                                        | Work the dispute in the billing dashboard              |

Voice origination surfaces the same codes when the pause/block flag is set:
`API /voice/calls/place` returns the 402 before the carrier dial is placed.

## 2. Recovery — manual reset (billing alerts)

A flagged alert does not auto-release — the gate holds until someone clears
it. Two buttons do so:

* **Dashboard manual reset.** Go to **Billing → Alerts** and use **Reset
  outbound** on the alerts page. It clears both the `outbound_paused` and
  `outbound_blocked` flags and resets the `outbound_block_reason`. The UI
  wires it to `POST /api/v1/billing/alerts/reset-outbound` (owner or admin
  only).
* **Disable the offending rule.** If a rule keeps firing too eagerly,
  either edit its threshold/action or delete it from the same page
  (`PATCH /api/v1/billing/alerts/:id`, `DELETE /api/v1/billing/alerts/:id`)
  to stop the trigger before you reset.

The same page also has a **Test fire** button
(`POST /api/v1/billing/alerts/:id/test)` — dry-runs a rule against today's
metrics without stamping it, so you can tune a threshold before it goes
live again.

<Warning>
  The reset endpoint clears the flag *only* — it does not replay queued sends
  that already failed. Re-issue the rejected requests from your application
  after the reset.
</Warning>

Auto-resume applies to exactly one cause (`wallet_empty`): it clears the
pause automatically once the wallet balance reads above zero. Dunning,
subscription-state, and billing-alert gates stay manual-reset-only — the
gate holds until you clear it.

## 3. Hard infra stops — provider and hold faults

These failures happen regardless of any flag and map to different recovery
paths:

| Code                              | Status | Cause                                                                                                                        | Recovery                                                                                                                             |
| --------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `BILLING_PROVIDER_ERROR`          | 502    | The upstream billing provider (Stripe or Orb) returned an invalid response or rejected a request                             | Retry once; the error is retry-safe. If it persists, contact support with the request id                                             |
| `VOICE_BILLING_HOLD_FAILED`       | 503    | The voice pre-flight hold could not be placed (Redis/Lua fault) so the call was refused instead of allowing an unbilled dial | Retry after the `details.retry_after_seconds` hint (30s); failed-closed by design so an infra fault never silently spends            |
| `VOICE_BILLING_CURRENCY_DEFERRED` | varies | The hold settled but the tenant wallet currency could not be resolved at settle time                                         | The CDR is quarantined uncharged; re-settlement resumes once currency resolution recovers — calls continue; no action usually needed |

`BILLING_PROVIDER_ERROR` reaches you from subscription billing, invoice
reads, refund operations, and any surface that proxies the provider. It is
safe to treat as transient.

## 4. Promo credits — trial-credit gates

The trial-credit surface is a manual grant lane; two specific codes cover
the platform-side failures. In addition there is a status read for the
"Claim trial credit" card:

| Code                              | Status | Cause                                                                      | Recovery                                                                        |
| --------------------------------- | ------ | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `TRIAL_CREDIT_CAP_EXCEEDED`       | 422    | The requested trial-credit grant exceeds the effective per-tenant cap      | Lower the request amount                                                        |
| `TRIAL_CREDITS_FAILED`            | 500    | The grant could not be applied because of an upstream infrastructure fault | Contact support; the full reason stays server-side                              |
| `TRIAL_CREDIT_STATUS_UNAVAILABLE` | 503    | The granted-already status read could not be resolved                      | Retry shortly; the claim control stays enabled, never falsely marked as claimed |

Note: self-service trial-credit grants are disabled — only a Devotel
super-admin can call `POST /api/v1/billing/trial-credits`. Callers from
tenant accounts get `403 FORBIDDEN` before reaching the trial-specific codes
above.

## 5. When to escalate

Open a support ticket when a reset does not clear the gate, or when
`BILLING_PROVIDER_ERROR` / `VOICE_BILLING_HOLD_FAILED` persists past the
suggested retry window. Include:

* Your **tenant ID** (dashboard → Settings → Organization; also
  `GET /api/v1/me` as `organizationId`).
* The **exact error code** and the **request ID** of a rejected call.
* The `details.reason` for pause/block routes.

## See also

* [Troubleshoot INSUFFICIENT\_BALANCE (402)](/troubleshooting/insufficient-balance)
* [Billing overview — alerts endpoints](/billing/overview)
* [Spend caps](/billing/spend-caps)
* [CDR export & billing reconciliation feed](/billing/cdr-export-billing-reconciliation)
