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

# Troubleshoot billing recovery codes (PAYMENT_REQUIRED, INSUFFICIENT_FUNDS, AUTO_TOPUP_payment/cap codes)

> The generic 402 billing ladder behind INSUFFICIENT_BALANCE: PAYMENT_REQUIRED (payment failure), INSUFFICIENT_FUNDS (hard wallet block), and the auto-top-up recovery codes AUTO_TOPUP_PAYMENT_FAILED and AUTO_TOPUP_MONTHLY_CAP_REACHED. Detect state via GET /billing/balance and wallet balance alerts, then fix per code.

# Troubleshoot billing recovery codes

Every billing 402 is one of four rungs on a single recovery ladder: your wallet
ran out (`INSUFFICIENT_BALANCE`), a payment failed (`PAYMENT_REQUIRED`), the
wallet hit a hard block (`INSUFFICIENT_FUNDS`), or auto-top-up stopped topping
up (`AUTO_TOPUP_PAYMENT_FAILED` / `AUTO_TOPUP_MONTHLY_CAP_REACHED`). The
[INSUFFICIENT\_BALANCE page](/troubleshooting/insufficient-balance) covers the
first rung; this page is the parent runbook for the rest.

<Note>
  Match on the `code` field, not the HTTP status — every rung returns `402`. A
  `PAYMENT_REQUIRED` does not mean the wallet is empty: it means the recharge
  attempt itself failed, so a top-up remains the fix but the diagnosis path is
  different.
</Note>

## 1. The billing-recovery ladder

| Code                             | Rung                | What it means                                                                      | Tenant-owned fix                                                                                                      |
| -------------------------------- | ------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `INSUFFICIENT_BALANCE`           | Wallet exhausted    | Pre-flight hold rejected on the 402 page                                           | [Work that branch](/troubleshooting/insufficient-balance) — top up, resend                                            |
| `PAYMENT_REQUIRED`               | Payment failure     | A charge attempt (card or crypto) rejected                                         | Update the payment method in Billing, retry the top-up                                                                |
| `INSUFFICIENT_FUNDS`             | Hard block          | Wire-level refusal, most often the fail-closed path in Verify fallback advance     | Same wallet fix — fund the wallet; do not blind-retry                                                                 |
| `AUTO_TOPUP_PAYMENT_FAILED`      | Auto-topup recovery | The scheduled off-session charge against the saved default payment method failed   | Update the saved payment method; auto-top-up re-arms on the next 15-minute tick                                       |
| `AUTO_TOPUP_MONTHLY_CAP_REACHED` | Auto-topup recovery | The calendar month's auto-charges would exceed the `max_monthly_minor` cap you set | Raise the cap, send `clear_cap: true` on `PUT /billing/auto-topup`, or top up manually until the UTC month rolls over |

`INSUFFICIENT_CREDITS` is the deprecated alias on the wallet-exhausted rung and
`PAYMENT_REQUIRED` is the generic name the API returns for the
payment-failure rung — both are stable contract strings you can match on in
client code.

## 2. Detect the state — balance query and wallet-balance alerts

`GET /api/v1/billing/balance` is the single state query you gate retries on:

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

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

* `balance_cents` — single most reliable detector. A **low but positive**
  balance with ` PAYMENT_REQUIRED` or `INSUFFICIENT_FUNDS` 402s means the
  pre-flight estimate is larger than your available balance (see the
  [INSUFFICIENT\_BALANCE branch table](/troubleshooting/insufficient-balance)).
* `outbound_paused` / `outbound_block_reason` — distinguishes a wallet-exhausted
  ladder rung from a tenant-configured billing-alert pause/block (see
  [billing-gate outbound blocks](/troubleshooting/billing-pause-block-recovery)).

Set a wallet-balance alert before relying on the poll: **Billing → Alerts** (or
`POST /api/v1/billing/alerts` with `threshold_type: "balance_floor"`) fires
email/SMS the moment balance drops below the floor you choose, so the first
402 never surprises you — see [spend caps and budget
alerts](/billing/spend-caps).

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/billing/alerts \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Wallet floor — page me before a 402",
    "threshold_type": "balance_floor",
    "threshold_value_cents": 2500,
    "action_on_hit": "notify",
    "notify_emails": ["ops@example.com"]
  }'
```

## 3. Fix per code

### `PAYMENT_REQUIRED` — update the payment method

1. Open **Billing** and check **Payment method**: the saved card bank-declined
   the last auto-top-up (or the pay-by-link checkout you opened lapsed).
2. Replace the saved card, or mint a new hosted checkout link
   (`POST /api/v1/billing/balance/top-up`) and complete it.
3. Retry the rejected send once, not repeatedly — the same code still fires
   while the method is in a dispute window.

### `INSUFFICIENT_FUNDS` — fund the wallet

1. `GET /api/v1/billing/balance` and read `balance_cents`.
2. If it sits at or near zero: top up (one-off Stripe Checkout or crypto) and
   resend. The code is thrown fail-closed on the API side even when it is the
   only blocking rung — Verify fallback advance and bulk-verify surfaces name
   it explicitly.
3. If it reads comfortably above zero, the estimate pre-flight on the specific
   surface (a long call, an expensive destination) exceeded available balance;
   gate the estimate (shorter `max_minutes`) or top up past the estimate.

### `AUTO_TOPUP_PAYMENT_FAILED` — fix the saved method, auto-recover

Auto-top-up recharges the wallet on a 15-minute tick once the balance crosses
`threshold_minor`. You get this code when the scheduled charge against the
saved default payment method is declined and auto-top-up was enabled.

1. In **Billing → Payment**, replace the saved default method — the next tick
   re-runs the recharge with the new method, no manual re-arm required.
2. Confirm with `GET /api/v1/billing/auto-topup` (the returned config keeps
   `enabled: true`; only the charge fails, the config does not disable).

### `AUTO_TOPUP_MONTHLY_CAP_REACHED` — raise or clear the cap

The optional `max_monthly_minor` ceiling auto-charges stop when hit, so the
wallet can run dry mid-month while the cap is enforced.

1. `GET /api/v1/billing/auto-topup` returns the saved `max_monthly_minor`.
2. Raise it in place: `PUT /api/v1/billing/auto-topup` with a larger
   `max_monthly_minor` (must remain ≥ `recharge_amount_minor`).
3. To remove the cap entirely you must pass `"clear_cap": true` on the same
   `PUT` — omitting the field, or sending it as `null`, preserves the saved
   cap (that is by design — a blanked form field cannot silently drop a
   limit).
4. If a manual top-up is safer for the rest of the month, use a one-off
   checkout and leave auto-top-up capped.

<Warning>
  Auto-top-up failures and wallet-hard-blocks cascade into the same 402 across
  every surface (send, verify, number renewal). The fix order is always: bring
  the wallet back above the estimate, then re-try the specific request.
</Warning>

## 4. When to escalate

Open a support ticket when:

* the ladder loops across several codes while `balance_cents` reads well above
  the failing estimates — that points at a hold-ledger fault, not a funding
  fault.
* an `AUTO_TOPUP_MONTHLY_CAP_REACHED` appears even though the saved
  `max_monthly_minor` reads `null` (i.e. you never set a cap) — the platform
  guard is tripping a default it should not have.
* a `PAYMENT_REQUIRED` persists across several payment-method swaps.

Include your tenant ID (dashboard → Settings → Organization, or `GET /me`
`organizationId`), the exact code(s), and the checkout/payment reference from
the Billing ledger when payment failures are involved.

## See also

* [INSUFFICIENT\_BALANCE (402)](/troubleshooting/insufficient-balance) — the
  wallet-exhausted rung of this ladder
* [Billing-gate outbound blocks](/troubleshooting/billing-pause-block-recovery) —
  tenant-configured pause/block flags and provider faults
* [Billing overview](/billing/overview) — wallet model, ledger, top-ups,
  invoices, auto-top-up
* [Spend caps and budget alerts](/billing/spend-caps) — wallet-balance alerts,
  spend ceilings, auto-cutoff
* [Auto-top-up API](/api-reference/billing#configure-auto-top-up) — config read/write/cap-clear
* [Error codes reference](/reference/error-codes) — `INSUFFICIENT_BALANCE`,
  `PAYMENT_REQUIRED`, `INSUFFICIENT_FUNDS`, `AUTO_TOPUP_PAYMENT_FAILED`,
  `AUTO_TOPUP_MONTHLY_CAP_REACHED`
