Skip to main content

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.
If your outbound messages return 402 INSUFFICIENT_BALANCE, work the insufficient-balance page instead — this page covers every stop beyond that one.

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