> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure wallet auto-top-up

> Set a threshold- and refill-amount pair so the wallet refills itself on a 15-minute scheduler tick — operators on unattended CPaaS stop being the weakest link, and a failed attempt surfaces a concrete cause you resolve instead of a silent pause.

# Configure wallet auto-top-up

Auto-top-up keeps the wallet funded without an operator watching the balance. You set a threshold (the balance that triggers a refill) and a refill amount, and a scheduler that runs every 15 minutes charges the saved default payment method the moment your balance dips below that line. Use it for the accounts that cannot afford a human on watch: an overnight campaign, an unattended dialer, a customer-facing voice flow that must not stop at 03:00.

Prefer auto-top-up over a manual top-up whenever the account is consumed by API traffic rather than interactive dashboard use. If a human authorizes every refill through [Billing & payments](/billing/overview), a missed refill becomes an outage; the scheduler removes the human from the critical path. Manual top-up remains the right tool for the very first payment (see prerequisites below) and for recovering a failed attempt.

## Prerequisites — a reusable payment method

Auto-top-up charges the organization's **default payment method** off-session. That requires two things saved before the first scheduler tick:

* A Stripe customer exists for the organization. The platform creates it on the first interactive checkout, so the prerequisite is completing one manual top-up at least once.
* A saved default payment method is on file — a card saved during checkout, or a bank debit (ACH) that has been approved. Check it with:

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/billing/payment-method \
  -H "X-API-Key: dv_live_sk_..."
```

```json theme={null}
{
  "data": {
    "brand": "visa",
    "last4": "4242",
    "exp_month": 12,
    "exp_year": 2028
  }
}
```

An empty `data` object here means the scheduler will skip every attempt with a `no_default_payment_method` error until a method is saved.

## Threshold and refill — set the pair

Configure the rule with `PUT /api/v1/billing/auto-topup`. All amounts are minor currency units (cents when the currency is `USD`):

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/billing/auto-topup \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "threshold_minor": 5000,
    "recharge_amount_minor": 100000,
    "max_monthly_minor": 300000,
    "max_topups_per_day": 2,
    "currency": "USD"
  }'
```

In that example the scheduler refills $1,000 whenever the balance drops below $50, constrained to at most \$3,000 of auto-charges per calendar month and at most 2 refills per UTC day.

Validation rules, enforced with a `422` on save:

* `threshold_minor` must be at least 100 (\$1.00).
* `recharge_amount_minor` must be at least 100 ($1.00) and at most $10,000 per single refill.
* `recharge_amount_minor` must be **greater than `threshold_minor`** — otherwise the balance would sit at the trigger line after every refill and fire another charge on the next spend. Pick a refill comfortably larger than the threshold.
* `max_monthly_minor`, when set, must be at least one full refill (`>= recharge_amount_minor`), otherwise the very first charge would breach the cap.
* `max_topups_per_day` is clamped to the range 1–100; leave it unset to use the platform default of 5 per day.
* `currency` must be a 3-letter code; today the wallet ledger credits USD only, so save `USD`. A non-USD value is accepted at save time but the scheduler will pause the rule with a `currency_not_supported` error.

The safety layer on top of your settings: a 5-minute cooldown between refills plus a hard limit of one refill per rolling hour, even when the balance keeps dipping under the threshold. Combined with the daily cap, a misconfigured rule can burn at most a bounded amount instead of charging in a loop.

Clear the monthly cap deliberately. Because the monthly cap is a safety control, setting `max_monthly_minor: null` alone does **not** clear it — the saved cap survives a blank-form submit. To remove the cap, pass `clear_cap: true` with the request:

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/billing/auto-topup \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true, "max_monthly_minor": null, "clear_cap": true }'
```

To disable the rule entirely, either `PUT` with `"enabled": false` (the threshold/refill draft survives for later re-enable), or `DELETE /api/v1/billing/auto-topup`, which also clears the runtime counters.

Response fields such as `last_charge_at`, `month_charged_minor`, `day_topups_count`, and `last_error` are runtime telemetry written by the scheduler — reads expose them, writes ignore them, so a save can never forge a "this month charged: \$0" reset.

## Notifications — success and failure

Every attempt, every outcome, is recorded in two places:

* **Audit log** ([signed audit log](/guides/audit-log)): `billing.auto_topup_triggered` on a refill attempt, `billing.auto_topup_failed` on a refusal, and `billing.auto_topup_skipped` when the rule self-pauses because your currency is not supported. A successful refill then credits the wallet via the payment webhook, which appears in the normal wallet ledger alongside manual top-ups.
* **The config itself**: the scheduler stamps `last_error` and `last_error_at` onto the rule after every failed attempt, and `GET /api/v1/billing/auto-topup` exposes both so a monitoring loop can alert on them. Success resets `last_error` to `null`.

Tip on a failure: rather than poll the GET in a cron of your own, combine the audit-log surface with [Usage-anomaly alerts](/billing/usage-anomaly-alerts) and route the `billing.auto_topup_failed` entries to your operations channel.

## Interactions with the other limits

Auto-top-up is one of four wallet-side controls, and it composes with each of the other three differently:

* **Low-balance renewal warnings.** The dashboard's low-balance alert is independent of auto-top-up; set your threshold above what your hourly burn consumes between warning intrusions, and the rule absorbs the warning entirely.
* **Org spend caps.** The ceilings in [Spend caps, budget alerts, and auto-cutoff](/billing/spend-caps) measure what the wallet **spends**, which is the opposite side of the ledger from what auto-top-up **refills**. Set them together: the spend cap bounds burn, the auto-top-up rule replenishes underneath it.
* **Per-API-key budgets.** Apply [Per-API-key spend budgets](/guides/per-api-key-spend-budgets) to any high-volume key to cap what a single integration can consume in a month, independent of how the wallet refills. The dashboard badge described in [Usage budgets and threshold alerts](/guides/api-key-usage-budget-alerts) is a browser-side tripwire for the request-volume side of usage; auto-top-up governs the money side.

## Recover a failed attempt

When `last_error` is non-null the rule stays armed — it retry-schedules the next tick and simply skips until the cause is resolved. The four canonical causes:

1. **`no_default_payment_method`** — no saved card or approved ACH. Complete one interactive top-up from Billing & payments to create the Stripe customer and save the method, then re-check `GET /billing/payment-method`.
2. **`payment_intent_requires_payment_method`** — the saved card was declined. Update the payment method to a working card.
3. **`payment_intent_requires_action`** — the charge needs customer authentication (SCA/3-D Secure). Top up interactively once to satisfy the bank's challenge; subsequent off-session refills resume automatically.
4. **`currency_not_supported`** — the saved currency is outside the supported set (today: USD). Update the rule to `USD`, or top up interactively and disable auto-top-up.

A fifth class — a raw Devotel or Stripe error code — is rare; it appears unchanged in `last_error`, so resolve the underlying issue (for example a declined refund or a wallet cap interrupt) and the next tick resumes.

## End-to-end walkthrough

A complete setup in four calls:

1. **Verify prerequisites** — `GET /api/v1/billing/payment-method` returns your saved method's brand, last four, and expiry.
2. **Enable the rule** — `PUT /api/v1/billing/auto-topup` with the threshold, refill, optional monthly cap, optional daily count, and `currency: "USD"` as above.
3. **Simulate the threshold** — the decision is what fires the refill, not a simulated spend; the 15-minute tick decides when the live balance minus `threshold_minor` reads below zero. To test the pipeline safely, set a deliberately high threshold above the current balance so the next tick immediately refills, then lower the threshold back to the production value.
4. **Inspect the outcome** — re-read `GET /api/v1/billing/auto-topup` and confirm `last_charge_at` advanced and `last_error` is `null`; then open [Billing & payments](/billing/overview) and confirm the matching credit in the wallet ledger, or the audit-log surface for the `billing.auto_topup_triggered` entry.

Between those steps the never-write rule applies: the scheduler stamps `last_charge_at`, `month_charged_minor`, and `day_topups_count` itself. A save payload that carries them is ignored by validation.
