Auto top-up
Auto top-up charges a saved card off-session to refill your credit balance whenever it drops below a threshold you set. Enable it so a long-running or unattended pipeline keeps dispatching instead of failing with 402 insufficient_credits partway through.
This page covers the three endpoints that manage it: read the config with GET /v1/billing/auto-topup, change it with PUT /v1/billing/auto-topup, and review the off-session charge history with GET /v1/billing/auto-topup/attempts.
When to enable it
Section titled “When to enable it”A batch is rejected with 402 at submit time if your balance can’t fund it. For a single ad-hoc batch that’s easy to handle by topping up manually. Auto top-up matters when you can’t be in the loop:
- Long-running or chained pipelines that submit many batches over hours or days and would otherwise stall mid-run.
- Unattended / scheduled jobs (cron, agents, CI) where no human is watching the balance.
- Bursty workloads where spend is hard to predict ahead of time.
When enabled, the balance is refilled back up to a target you choose as soon as it falls below your threshold, so submits keep succeeding.
Configuration fields
Section titled “Configuration fields”The configuration object (auto_topup) uses these fields. Money values are returned as objects ({ "currency": "usd", "amount": "25.00" }); when you write them via PUT, you send plain USD-dollar numbers.
| Field | Type | Description |
|---|---|---|
enabled | boolean | Whether auto top-up is active. |
threshold | money | Balance that triggers a refill. |
target | money | Balance to refill up to. Must exceed threshold. |
payment_method_id | string | The saved card charged off-session. Must belong to your org. |
max_per_day | integer | null | Maximum auto top-ups per day; null means no cap. |
monthly_ceiling | money | null | Maximum total auto top-up spend per month; null means no cap. |
oncredit_exhausted | block | pause | What happens when credits still run out: hard-block new batches, or pause the org gracefully. |
configured | boolean | Read-only. Whether a config row exists yet. |
consecutive_failures | integer | Read-only, system-managed. Resets on a successful charge. |
paused_reason | string | null | Read-only, system-managed. Set when repeated failures auto-pause top-up. |
Read the current config
Section titled “Read the current config”GET /v1/billing/auto-topup returns the org’s auto top-up configuration under an auto_topup key. Reading is authorized with either a customer API key or a signed-in dashboard session.
curl https://api.batchrouter.com/v1/billing/auto-topup \ -H "Authorization: Bearer $BATCHROUTER_API_KEY"const res = await fetch("https://api.batchrouter.com/v1/billing/auto-topup", { headers: { Authorization: `Bearer ${process.env.BATCHROUTER_API_KEY}` },});const { auto_topup } = await res.json();console.log(auto_topup.enabled, auto_topup.threshold, auto_topup.target);import os, requests
res = requests.get( "https://api.batchrouter.com/v1/billing/auto-topup", headers={"Authorization": f"Bearer {os.environ['BATCHROUTER_API_KEY']}"},)auto_topup = res.json()["auto_topup"]print(auto_topup["enabled"], auto_topup["threshold"], auto_topup["target"])A representative response:
{ "auto_topup": { "org_id": "org_...", "configured": true, "enabled": true, "threshold": { "currency": "usd", "amount": "10.00" }, "target": { "currency": "usd", "amount": "50.00" }, "payment_method_id": "pm_...", "max_per_day": 3, "monthly_ceiling": { "currency": "usd", "amount": "500.00" }, "consecutive_failures": 0, "paused_reason": null, "oncredit_exhausted": "block" }}Update the config
Section titled “Update the config”PUT /v1/billing/auto-topup performs a partial merge: only the fields you send are changed; everything else is left as-is. Money fields are sent as plain USD-dollar numbers (e.g. 50 for $50.00).
Enabling auto top-up has hard prerequisites. The PUT will reject the change unless all of these hold:
-
Your account email is verified.
-
A
thresholdis set, and atargetgreater than the threshold is set. -
A saved
payment_method_idthat belongs to your org is set. -
The environment supports off-session charging. If it doesn’t, you’ll get
503 auto_topup_unavailable.
curl -X PUT https://api.batchrouter.com/v1/billing/auto-topup \ -H "Authorization: Bearer $BATCHROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "threshold": 10, "target": 50, "payment_method_id": "pm_...", "max_per_day": 3, "monthly_ceiling": 500 }'const res = await fetch("https://api.batchrouter.com/v1/billing/auto-topup", { method: "PUT", headers: { Authorization: `Bearer ${process.env.BATCHROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ enabled: true, threshold: 10, target: 50, payment_method_id: "pm_...", max_per_day: 3, monthly_ceiling: 500, }),});const { auto_topup } = await res.json();import os, requests
res = requests.put( "https://api.batchrouter.com/v1/billing/auto-topup", headers={"Authorization": f"Bearer {os.environ['BATCHROUTER_API_KEY']}"}, json={ "enabled": True, "threshold": 10, "target": 50, "payment_method_id": "pm_...", "max_per_day": 3, "monthly_ceiling": 500, },)auto_topup = res.json()["auto_topup"]A successful PUT returns the merged config in the same { "auto_topup": { … } } shape as the GET. To turn auto top-up off, send { "enabled": false } — the rest of the config is retained.
Review charge attempts
Section titled “Review charge attempts”GET /v1/billing/auto-topup/attempts returns recent off-session charge attempts, newest first, under a data array. Use it to confirm a refill went through or to diagnose a failed charge. Pass an optional limit query parameter (1–200, default 50).
curl "https://api.batchrouter.com/v1/billing/auto-topup/attempts?limit=20" \ -H "Authorization: Bearer $BATCHROUTER_API_KEY"const res = await fetch( "https://api.batchrouter.com/v1/billing/auto-topup/attempts?limit=20", { headers: { Authorization: `Bearer ${process.env.BATCHROUTER_API_KEY}` } },);const { data } = await res.json();for (const attempt of data) { console.log(attempt.created_at, attempt.status, attempt.amount);}import os, requests
res = requests.get( "https://api.batchrouter.com/v1/billing/auto-topup/attempts", headers={"Authorization": f"Bearer {os.environ['BATCHROUTER_API_KEY']}"}, params={"limit": 20},)for attempt in res.json()["data"]: print(attempt["created_at"], attempt["status"], attempt["amount"])Each attempt records the trigger_balance (what the balance was when the refill fired), the amount charged, the payment_method_id, the Stripe payment intent, a status (pending, succeeded, requires_action, or failed), and a failure_code when the charge didn’t go through. A successful attempt also carries a credited_transaction_id linking to the credit that landed on your balance. See the API reference for the full field list.