Skip to main content

Billing overview

Orbit runs on a prepaid wallet. Every organization holds a single USD wallet that funds messaging, voice, video, and AI usage. Charges are deducted from the wallet in real time as usage happens, and every deduction is recorded in an append-only ledger you can read, download, and reconcile. This page maps the whole billing surface — wallet, top-ups, plans, invoices, usage, alerts, contracts, and refunds — and links each concept to its API endpoints and deeper guides.
  • The dashboard exposes the same surface under Billing (alerts, invoices, statements, usage, cost-centers, pay-by-link, pricing, calculator, and the what-if simulator).
  • The full request/response reference for every endpoint named here is in the Billing API reference.
Every walkthrough below ships as a <CodeGroup> with three tabs — cURL, Node.js (TypeScript), and Python. The Node tab prefers the typed @devotel-orbit/node helper where the SDK ships one (getBalance, topUp); where the SDK has no typed billing helper yet (pay-by-link, plans, transactions, crypto top-up) it falls back to plain fetch. The Python tab uses plain requests per the sample-writing guide, so it runs without installing the SDK. All read the key from ORBIT_API_KEY and every response carries the same { data, meta } envelope (meta.request_id, meta.timestamp).

1. Wallet & prepaid model

Your wallet holds prepaid funds. Usage — per message, per voice minute, per AI token — debits the wallet as it happens; top-ups, refunds, and grants credit it. Read the live balance plus the account’s pause state here — call it before every send batch to gate on funds, and on your billing dashboard to render the same number the Orbit dashboard shows: GET /api/v1/billing/balance
200
An error worth branching on: when the wallet is empty and outbound is paused, every send returns HTTP 402 with code: "SENDING_PAUSED" — branch on the code, not the status, and top up before you retry. A 429 RATE_LIMITED on this read carries error.retry_after seconds; back off that long before polling again. See the full balance reference for field semantics. The balance is returned in dollars, whole cents, and exact integer micro-cents (balance_micro_cents = cents × 1,000,000), along with the ISO 4217 currency the ledger is denominated in. Use balance_micro_cents when subtracting sub-cent rates (per-email, per-token) from the balance in integer math. Pause-state flags explain whether outbound sending is available:
  • outbound_paused — true when sending is paused (balance exhausted, a billing alert’s pause action, or repeated payment-method failures). Outbound sends return SENDING_PAUSED (HTTP 402) while paused.
  • outbound_block_reason — why the pause is in effect, when set.
  • payment_failure_count — consecutive Stripe payment failures (0–3) driving dunning; at 3 the account is frozen until the card is updated.
When degraded: true appears in the response, the value is a last-known fallback during a short availability blip — the dashboard shows a “Balance recently degraded” notice rather than a phantom zero.

2. Top-up flows

Hosted card checkout. POST /api/v1/billing/balance/top-up mints a Stripe Checkout session and returns the hosted URL; the wallet is credited when the payment settles (topped up immediately on return via the confirm endpoint, even if the webhook is delayed). Requires the owner, admin, or billing role. Use this whenever a payer funds the wallet with a card — the Idempotency-Key header is required, and re-using it returns the original Checkout URL instead of a duplicate session.
200
An error worth branching on: an HTTP 409 here means the Idempotency-Key was re-used with a different (amount, currency) — the replay was rejected, not duplicated. Treat 409 as “you already have a Checkout URL for this key”; re-fetch with the same key to get the original session instead of minting a new one. Crypto top-up. POST /api/v1/billing/balance/top-up-crypto mints a hosted invoice for Bitcoin, USDT, ETH, and other coins, settling to the wallet in USD. Use this when a payer wants to fund the wallet with crypto instead of a card. See Cryptocurrency payments for the full flow, status meanings, and cancellation semantics.
200
An error worth branching on: the cancellation endpoint (POST /api/v1/billing/balance/top-up-crypto/:intentId/cancel) returns HTTP 402 PAYMENT_REQUIRED when the on-chain payment has not yet confirmed enough to cancel cleanly, and HTTP 409 when a payment is already in flight (code: "PAYMENT_IN_FLIGHT"). Treat 402 as “wait for confirmation before cancelling”; treat 409 as a terminal state you should surface, not retry. Collecting a customer payment. POST /api/v1/billing/pay-by-link mints a hosted checkout link and renders a request-to-pay message for the best reachable channel (SMS, RCS, WhatsApp, email, or voice IVR read-out). Orbit returns the rendered message and URL — the send goes through your own channel pipeline. Use this when you collect payments from your customers, not for funding your own wallet.
200
An error worth branching on: a HTTP 422 here is almost always an amountMinor below the provider’s per-currency minimum (50 minor units for USD/EUR) — read error.details.field and bump the amount, never retry the same body. All three are covered in the API reference — parameters, idempotency semantics, and the crypto-fee policy. Currency conversion. Paying in a currency other than your wallet currency converts at credit time, with the applied rate recorded on the transaction. See Wallet top-up currency conversion. Choose Cryptocurrency or Credit / debit card in the payment-method selector on Dashboard → Billing to top up manually.

3. Auto-top-up

Auto-top-up charges your saved payment method off-session whenever the balance crosses a threshold, so outbound never stops for want of funds. Configure it from Dashboard → Billing → auto-replenish, or via the API. The surface is a three-call triad — read the config, write it, and (when needed) clear it:
  • GET /api/v1/billing/auto-topup — read the current config.
  • PUT /api/v1/billing/auto-topup — create or update the rule.
  • DELETE /api/v1/billing/auto-topup — disable it and clear its state.
Use this when you want outbound sending to survive a balance dip without a human recharging manually. Read first so your PUT preserves any fields you do not intend to change: 1. Read the current config
2. Create or update the rule
200
3. Disable and clear state
An error worth branching on: a HTTP 422 on the PUT means recharge_amount_minor did not exceed threshold_minor (or a cap/validation rule failed) — read error.details.field and fix the amounts instead of retrying the same body. The auto-top-up reference adds the clear-cap variant and the validation rules. Semantics when enabled is true:
  • threshold_minor — the balance level (minor units, e.g. cents) that triggers a top-up. Minimum $1.00.
  • recharge_amount_minor — the amount charged when triggered. Must exceed the threshold so each top-up lifts the balance back above the trigger (otherwise you would get charged repeatedly).
  • max_monthly_minor — optional monthly cap. Persisting it is explicit: omitting the field (or sending null) keeps any saved cap; removing a cap requires "clear_cap": true.
  • max_topups_per_day — optional per-day cap (default 5) bounding runaway-loop exposure.
Safety rails apply regardless of config: a 5-minute cooldown and a one-per-hour limit between auto-charges. The evaluator runs on a 15-minute schedule and uses the org’s default off-session payment method. Crypto top-ups are intentionally not supported for auto-replenish — the volatility and lack of an on-file credential make automatic charges impossible (see Cryptocurrency payments).

4. Plans & subscriptions

Orbit is a unified pay-as-you-go platform — plan tiers are retired by design, so the catalog intentionally lists one default plan rather than a tier matrix. GET /api/v1/billing/plans returns the default plan (payg), its included capabilities (every channel on one wallet), and its starting limits (2 team seats, 1,000 requests/second sustained). It is informational pricing that any authenticated session can read, including a brand-new owner on onboarding. Use it to render a pricing or onboarding screen before a workspace activates.
200
An error worth branching on: this read is safe to poll on a dashboard loop, but it is still rate-limited — on HTTP 429 read error.retry_after (seconds) from the envelope and hold that long before the next poll instead of hammering the endpoint. Each plan also reports the free-trial credit, the entitlement limits, and the entitled channel/capability keys — the full field list sits behind the same endpoint. The subscription lifecycle endpoints exist for enterprise contracts and for legacy lifecycle actions:
  • POST /api/v1/billing/subscription — cancel, reactivate, or change_plan with an audit-logged reason (owner/admin/billing role).
  • POST /api/v1/billing/checkout — mint a hosted checkout session for a one-off enterprise contract price.
  • POST /api/v1/billing/portal — open the payment-method portal for the org’s Stripe customer.
  • GET /api/v1/billing/payment-method — read the saved payment method.
Free trial credits (where enabled) are granted automatically during onboarding; GET /api/v1/billing/trial-credits/status reports whether the org has claimed them.

5. Invoices & statements

Invoices. GET /api/v1/billing/invoices lists the org’s invoices, and GET /api/v1/billing/invoices/:id returns line-item detail. Card and crypto top-ups both produce receipts under Dashboard → Billing → Invoices, with payment method, network/coin detail for crypto, and USD-equivalent recorded at confirmation time. Monthly statements. Orbit aggregates the prepaid-wallet ledger into native monthly statements — opening balance, top-ups, usage-by-channel, closing balance — for pay-as-you-go tenants. GET /api/v1/billing/statements lists monthly summaries; GET /api/v1/billing/statements/:period (e.g. 2026-08) returns detail; GET /api/v1/billing/statements/:period/download exports CSV or JSON. Owner/admin role. Dashboard → Billing → Statements is the same data. Revenue recognition. For finance teams, GET /api/v1/billing/revenue-recognition/schedule produces the per-contract straight-line recognition schedule for committed-use commitments and recurring subscription invoice lines; GET /api/v1/billing/revenue-recognition/summary rolls recognized-in-period vs. remaining-deferred as of a reporting date. Read-only, billing-role. See Revenue recognition for the model, field reference, dashboard walkthrough, and month-end workflow.

6. Usage, burn rate, and spend alerts

Usage. GET /api/v1/billing/usage returns the current-billing-period usage metrics (name, usage, limit per metric). For a per-channel breakdown with cost and volume, use GET /api/v1/billing/usage-by-channel with group_by axes channel | country | campaign | sender | cost_center; the cost_center tag set on sends enables chargeback attribution, and GET /api/v1/billing/chargeback-rollup rolls the period up by department. Dashboard → Billing → Usage is the same surface. Transactions ledger. GET /api/v1/billing/transactions reads the append-only wallet ledger with cursor pagination — every credit and debit. Use it to reconcile deductions against what the wallet actually recorded. Per-channel pricing rules are documented in the Billing API reference.
200
An error worth branching on: paging with a malformed or expired next_cursor returns HTTP 422 with code: "INVALID_CURSOR" — drop the cursor and restart from the first page rather than retrying it. Burn rate. GET /api/v1/billing/burn-rate returns average daily spend and projected days remaining before the wallet hits zero (the dashboard balance widget’s “X days remaining” line). GET /api/v1/billing/spend-series returns the same window plus a forward projection and anomaly flags. Spend alerts. Billing alerts watch spend or balance thresholds and act when crossed. Config is org-owned; the scheduler evaluates thresholds on a 10-minute tick.
  • GET /api/v1/billing/alerts / GET /api/v1/billing/alerts/:id — list and read.
  • POST /api/v1/billing/alerts — create (thresholds: spend_percent, spend_amount, balance_remaining, daily_spend; recipients by email and/or SMS; action_on_hit: notify, pause_outbound, or block_outbound; cooldown up to 30 days).
  • POST /api/v1/billing/alerts/:id/test — dry-run test-fire.
  • GET /api/v1/billing/spend-anomaly and GET /api/v1/billing/spend-anomaly/ledger — velocity-anomaly detection that flags channels projecting a spend surge above your trailing baseline.
The full model — how the three instruments (threshold alerts, burn rate, velocity anomaly) complement each other, the detector’s window math, the self-expiring mitigation throttle, and the on-call escalation bridge — is Spend alerts, burn rate, and the velocity-anomaly model. Alerts are tenant-owned controls: you decide the threshold and the action. Prefer notify so an operator reviews the hit; pause_outbound pauses outbound sending until the alert is reset in the dashboard.

7. Committed-use contracts

Enterprise tenants on a negotiated monthly commitment can watch the drawdown meter: GET /api/v1/billing/commitment reports how much of the monthly commit has been consumed this period, a linear run-rate projection, and the projected end-of-period true-up (minimum-commit shortfall when under pace, overage when exceeded).
The commitment is a contract term set by your Devotel account team — not a self-serve setting — and the endpoint moves no money. Tenants without a commitment receive commitment: null and the dashboard panel self-hides. For pricing forecasting you might also use GET /api/v1/billing/volume-tier-preview (see what committing more volume earns), GET /api/v1/billing/budget-cap (the org’s monthly budget cap for campaign checks), and POST /api/v1/billing/whatif-pricing/preview (re-price real usage against a candidate rate card). All are read-only.

8. Refunds

Crypto refunds. Crypto payments are final and are not reversible from the dashboard; a human operator processes each refund via a manual payout. See Cryptocurrency refunds for the request flow and the same-chain wallet requirement. Card refunds. Owner-role endpoints wrap Stripe refunds against the original charge, subject to a 30-day window and unused-balance-only scope:
  • POST /api/v1/billing/refunds — create a refund request (owner only).
  • GET /api/v1/billing/refunds / GET /api/v1/billing/refunds/:id — list and poll request status.

Where next