Troubleshooting: sends rejected with INSUFFICIENT_BALANCE (402)
Orbit is prepaid pay-as-you-go: every outbound message, call minute, and
agent invocation debits your wallet, and the wallet is checked before the
send leaves the queue. When the check cannot clear, the API rejects the
request with a 402 and code INSUFFICIENT_BALANCE — the send never
reaches the provider. This page explains how that pre-flight works, what
each cause looks like, and how to get the wallet funded (and stay funded)
before you re-send.
Linear sends (a message POST, a call originate) fail fast in the request.
Queued sends (campaigns, scheduled messages) surface the same rejection
on the per-message row as a terminal failed status with code
INSUFFICIENT_BALANCE.
How the wallet pre-flight works
Before a send is dispatched, Orbit estimates its worst-case cost and
places a hold on the wallet for that amount:
- Estimate. The per-channel rate for the destination (messaging) or
the configured per-minute rate (voice) is resolved, and the worst-case
cost is computed. For WhatsApp Calling this is
max-minutes × per-minute rate, and the sending surface caps that estimate explicitly.
- Hold. The estimated amount is held against the available balance.
If the available balance cannot cover the hold, the request is refused
with
INSUFFICIENT_BALANCE and nothing is dispatched.
- Settle. When the send completes (or fails on the wire), the hold is
released and the actual cost is debited; the unused estimate remainder
returns to the available balance.
Because the check compares the estimate against the available balance
(current balance minus outstanding holds), a burst of concurrent sends can
push you into a 402 even when the headline balance looks sufficient.
Where to see balance and holds
The dashboard’s Billing section shows the current balance, recent
ledger entries, and outstanding holds. The Billing API returns the same
values — see the Billing overview for the read
endpoints and ledger semantics. If a small set of writes is holding a
large share of the wallet, the ledger view is where you find them.
Causes, mapped to fixes
Work the table top to bottom — the first row that matches your setup is
the fix.
INSUFFICIENT_CREDITS is deprecated; new integrations should match on
INSUFFICIENT_BALANCE. Both appear in the
error codes reference, which also lists the
fail-closed BALANCE_SERVICE_UNAVAILABLE (503) and the WhatsApp-calling
pre-flight variant that can return either 402 or 503.
Top up and re-send
- Open Billing in the dashboard and confirm the balance reads below
the estimate the send requires.
- Choose Top up, pick an amount that covers your expected volume
(top-ups are one-off Stripe Checkout payments; credit never expires),
and complete checkout.
- Wait for the confirmation — the ledger entry posts as soon as the
payment clears.
- Re-send the rejected requests. For queued sends that failed with
INSUFFICIENT_BALANCE, re-issue them from your application; the
platform does not auto-replay terminal failures.
Do not blind-retry a 402. Without new funds each retry re-runs the same
pre-flight and returns the same rejection — and if the retry loop fans
out, every attempt still burns a pre-flight estimate. Gate retries on a
fresh balance read, or better, enable auto-top-up so the wallet refills
without your loop noticing.
Auto-top-up refills the wallet automatically so sends stop failing at the
pre-flight. It is entirely tenant-configured — you set the trigger, the
recharge amount, the payment method, and the ceilings, and no support
ticket is required to change any of it.
- Open Dashboard → Billing → auto-replenish.
- Set the threshold: when the balance drops below this amount, a
recharge fires.
- Set the recharge amount charged to your saved payment method.
- Optionally set spend ceilings (a daily or monthly cap on top-ups) so a
runaway integration cannot drain the card — details in
Spend caps, budget alerts, and auto-cutoff.
When auto-top-up is on and the payment method is healthy, a low balance
triggers a recharge before the next send hits the pre-flight. If the
recharge itself fails (declined card), the rejection pattern returns —
update the payment method and the trigger fires again on the next low
reading.
When to escalate
Open a support ticket when the rejection persists after a funded top-up,
or when every rejection is a BALANCE_SERVICE_UNAVAILABLE 503 that outlasts
a few minutes of retries. Include:
- Your tenant ID (dashboard → Settings → Organization; also returned
by
GET /api/v1/me as organizationId).
- The exact error code (
INSUFFICIENT_BALANCE or
BALANCE_SERVICE_UNAVAILABLE) and the request ID of one rejected
call.
- For a payment failure: the checkout/payment reference shown on the
Billing page’s ledger entry.
That set lets support pull the wallet ledger, the pre-flight decision,
and the payment attempt without a back-and-forth.
See also