The dunning lifecycle model
When a subscription charge fails, Orbit does not pause your outbound on the first failure. It counts. A per-organization dunning counter tracks consecutive failed subscription payments, and only the third consecutive failure freezes outbound sending with the pause reasondunning_failed_3x.
This page is the model behind that number. The pause-gate taxonomy lives on
the outbound pause gate and free-channel exemption;
the refusal → recovery → poll loop lives on
outbound pause and recovery.
This page owns the counter’s state machine: how it increments, when it
freezes, why a card update leaves it untouched, and which event clears it.
The payment_failed counter lifecycle
Every failed subscription charge increments the counter by one. The subscription retries that the payment processor runs across a few days each register their own failure, and the counter climbs 1, 2, 3. A successful charge at any point clears it back to zero — the counter counts consecutive failures, not lifetime failures, so one settled invoice at count 1 or 2 resets the window. The poll endpoint names the live count.GET /api/v1/organization/account-status derives its restrictions from the same
organization row the gate reads, and while it reports the froze restriction,
the raw count is the state machine’s visible cursor. Below the threshold
there is no freeze — only the count.
The three-failures freeze
At count 3 the freeze flips in the same write that incremented the counter — one statement, so a race between two failed-charge events can never double-freeze or both notify. The organization’s outbound pauses with reasondunning_failed_3x, and every send on a paid channel rejects with 402
SENDING_PAUSED. The increment, the freeze, and the notification that the
freeze fired happen exactly once, even when the processor redelivers the
failure event.
The freeze carries through to the public surface deterministically:
GET /api/v1/organization/account-status reports the restriction with the
billing code and remediation update_payment_method. The pause flips only
when the threshold is crossed — the count just predicts it.
Counter-forward — a card update never resets
Updating the payment method deliberately leaves the counter where it was. The idea is to prevent pause-flapping: if a card update reset the counter to zero, an account could dance between froze and unfreeze by re-entering a doomed card each cycle. The freeze is sticky and the counter is forward-only — a charge either settles or it does not, and only settling resets. The settlement check is narrow on purpose: only a subscription renewal or a plan-change charge that actually succeeded clears the counter. A $0 metered usage invoice, a manual invoice, or any other non-subscription payment event does not — a settled micro-invoice never unfreezes an account whose subscription card keeps failing. This is what keeps the freeze honest.Resolution — only a successful charge lifts the hold
Two resets exist, and each clears the counter back to zero and removes the dunning freeze when it was the reason:- A successful subscription payment. When the retried charge settles, the payment-success event resets the counter and drops the freeze if — and only if — the freeze was the dunning one. A freeze set by an admin for any other reason survives untouched.
- Reactivate or change plan. Reactivating a canceled subscription or moving to a new plan is treated as a fresh billing relationship: both paths start the counter from zero again so a re-activated account is never one failure away from an immediate freeze.
wallet_empty pauses, and only those. All
credit routes (card top-up, crypto, auto-top-up, refunds, operator-issued
credits) funnel through a shared resume block that touches only
wallet_empty-marked pauses; a dunning_failed_3x hold falls outside its
guard by design. Positive balance is never the unlock condition for
dunning.
How dunning interacts with other subscription states
Dunning is one hold among several, and the restrictions add up rather than replace each other. Apast_due or unpaid subscription state and a
dunning freeze are different facts on the same account — the status endpoint
reports both, ordered so the most limiting restriction surfaces first. None
of the following overlap with each other:
wallet_empty— a balance-driven soft pause that a top-up clears; dunning is an account-lifecycle hold that a top-up cannot clear.billing_alert:<id>:<name>— a spend-threshold hold you resolve under Dashboard → Billing → Alerts; nothing to do with charge failures.- Admin hold, suspension, dispute — hard holds on the organization that a freeze reset will not disturb; the dunning reset only ever touches freezes it set itself.
Poll-loop for recovery
Treat every 402 as terminal, then drive the loop:- Update the payment method under Settings → Billing.
- Settle the outstanding invoice. The retried charge runs against the new card; once it succeeds the counter resets and, if the freeze was dunning, the freeze clears inline.
- Poll the status endpoint until the dunning restriction disappears:
Read the model alongside the gate chain
The freeze is one cause in the wider outbound gate. The ordered pre-flight → flags → fund-path → decrement chain that every send walks is narrated on the billing gate chain; its stage-2 flags gate is where a failed third charge surfaces as a 402. The full cause taxonomy — which holds exempt free channels and which do not — is on the pause gate and free-channel exemption.Related pages
- Outbound pause and recovery — the refusal → recovery → resume → poll loop across every pause cause.
- The outbound pause gate and free-channel exemption — the hold classes and their free-channel posture.
- The billing gate chain — the ordered stages every send walks, where the dunning freeze fires at stage 2.
- Account status API reference — the endpoint the recovery loop polls.