Skip to main content

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 covers the first rung; this page is the parent runbook for the rest.
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.

1. The billing-recovery ladder

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:
  • 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).
  • outbound_paused / outbound_block_reason — distinguishes a wallet-exhausted ladder rung from a tenant-configured billing-alert pause/block (see billing-gate outbound blocks).
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.

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

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