Skip to main content

Crypto top-up API lifecycle

The cryptocurrency payments guide walks the dashboard flow. This page is the same lifecycle driven from an integration: you create the top-up, open the hosted invoice URL for the payer, poll the intent until it settles, and optionally cancel it while the invoice is still unfunded. Every sample below is copy-pasteable. The three endpoints require an API key carrying the billing:write scope (or an owner, admin, or billing dashboard session) and are rate-limited as money-moving operations.

1. Create a top-up intent

POST /api/v1/billing/balance/top-up-crypto mints a NOWPayments hosted invoice and returns its URL. Idempotency-Key is required: re-submitting the same key returns the original invoice instead of minting a new one, and re-using the key with a different (amount, currency) returns 409 IDEMPOTENCY_KEY_REUSED.
200
  • amount is in minor units (cents): minimum 100 (1.00),maximum1000000(1.00), maximum `1000000` (10,000).
  • currency accepts only usd today — the wallet ledger is USD-denominated.
  • successUrl and cancelUrl must be on a trusted origin (orbit.devotel.io).
  • feePaidByUser reflects the network-fee policy: for top-ups of 50orlessOrbitabsorbsthefee(feePaidByUser:false,feeCentsistheabsorbedamount);above50 or less Orbit absorbs the fee (`feePaidByUser: false`, `feeCents` is the absorbed amount); above 50 the fee is added on top of amount at the hosted invoice (feePaidByUser: true, feeCents: 0).
  • If crypto top-up is not yet enabled for your account, the endpoint returns 503 SERVICE_UNAVAILABLE — use Stripe Checkout in the meantime.
Open checkoutUrl in a browser for the payer. The coin and the exact crypto amount are chosen on the hosted page; the intent settles once the network confirms the transfer.

2. Poll the status

GET /api/v1/billing/crypto-topup/{intentId}/status returns the current state of the intent. Poll it with a few seconds’ spacing while the payment settles; the endpoint self-heals a dropped provider callback, so the poll always reflects the latest known state. Read scope (billing:read) is sufficient for this call.
200
Once the payer picks a coin on the hosted page, NOWPayments reports the transfer details on its callback and the intent metadata carries them: order_id, plus on-chain fields such as pay_address, pay_amount, and expires_at, as the provider surfaces them — not every coin reports every field. A 404 means the intent does not exist or belongs to a different organization. Stop polling when paymentStatus reaches a terminal state:
  • Success terminal: finished — the wallet is credited; refunded.
  • Retry terminal: failed, expired, cancelled — create a new intent to try again. See the state table linked below before retrying.

3. Cancel a pending top-up

POST /api/v1/billing/crypto-topup/{intentId}/cancel cancels an intent while it is still unfunded. Cancellation succeeds only in waiting or confirming; once the payment is confirmed, sending, finished, refunded, failed, or already expired, the cancel is rejected and the response carries the live status.
Success:
200
Too late — the payment is already settling:
409
details.current_status always shows the live state (finished, confirmed, sending, refunded, failed, expired, or cancelled), so re-poll the status endpoint after a 409. Cancellation is Orbit-side only — the provider has no invoice-cancel API, so the receiving address stays open — and a cancel never loses money: if funds arrive after you cancel, the settlement callback overrides cancelled and credits your wallet exactly once.

4. Status taxonomy

The full state machine — every status, its meaning, and which states allow a cancel — is maintained on the guide: Status meanings. The common path is waiting → confirming → confirmed → sending → finished.

5. Webhook events on settlement

When the top-up reaches finished and the wallet is credited, Orbit delivers balance.topped_up to your webhook endpoints, tagged payment_method: "crypto_nowpayments" with amount_cents and currency in the payload. The same event fires for Stripe (card) top-ups, so one handler covers both funding sources. Subscribe to it under Dashboard → Developers → Webhooks; the full billing event list is in the webhook event catalog. Use the webhook instead of long-running polling: create the intent, show the invoice, and treat balance.topped_up as the definitive receipt that the wallet moved. Poll the status endpoint as a fallback when the event has not arrived yet.

6. Sandbox behavior

Sandbox mode short-circuits messaging and voice sends before they touch a carrier; money endpoints behave differently. Crypto top-ups run against the real NOWPayments service — Orbit’s staging integration points at the NOWPayments sandbox environment (api-sandbox.nowpayments.io), where invoices behave like the real thing without moving real funds. In practice:
  • There are no magic numbers for crypto top-ups — the magic-number convention applies to message, voice, and number-purchase simulation, not to billing.
  • On developer staging: exercise both lifecycle paths for free (create → poll, and create → cancel) against the NOWPayments sandbox environment.
  • On production: cancel an unfunded intent (step 3) to test your lifecycle handling without spending funds. Never send test transfers on a live account — settled crypto is non-refundable without operator action.