Search docs

Find any page, endpoint, or guide.

Charge a saved card to top up the wallet

Alpha
POSThttps://api.voxrouter.ai/v1/billing/topup

Charge a previously-saved Stripe payment method off-session and credit the caller's organization wallet. Accepts both `vr_session_*` (CLI) and raw better-auth session tokens (dashboard server-side). `pk_*` keys are rejected — minting credit purchases from an API key would be a privilege-escalation footgun. Idempotency is REQUIRED. Pass a per-attempt `idempotency_key` — Stripe uses it to dedupe retries. The SDK generates a fresh UUID per call when callers don't supply one. If the card requires a 3D Secure challenge, the response is `402 stripe_3ds_required` with a URL pointing at the dashboard's PaymentIntents flow. The CLI prints the URL; the user finishes the challenge in a browser, after which the card becomes off-session-friendly for subsequent topups.

bash
curl -X POST https://api.voxrouter.ai/v1/billing/topup \
  -H "Authorization: Bearer $VOXROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "amount_cents": 0,
      "payment_method_id": "string",
      "idempotency_key": "string"
    }'

Headers

AuthorizationstringRequired
Bearer token. Send as Authorization: Bearer pk_....
Content-TypestringRequired
Must be application/json.

Body

amount_centsintegerRequired
Amount to charge, in USD cents. Range $10–$1000.
payment_method_idstringRequired
Stripe `pm_*` id of a saved card belonging to the caller's org. Get from `GET /v1/billing/methods`.
idempotency_keystringRequired
Per-attempt key Stripe uses to dedupe retries. REQUIRED — the SDK auto-generates a fresh UUID per call when the caller doesn't supply one.

Response

Charge succeeded; webhook will credit the wallet.

json
{
  "ok": false,
  "payment_intent_id": "string",
  "amount_cents": 0
}
okbooleanRequired
payment_intent_idstringRequired
Stripe `pi_*` id of the created PaymentIntent.
amount_centsintegerRequired
Echoed back so the caller can confirm what was charged.

Errors

Non-2xx responses return a JSON body with a machine-readable error code and an optional details string.

StatusMeaning
400Request body failed validation or model string is malformed.
401Missing or invalid API key.
402Stripe declined the charge. Either the card was rejected (`error: "card_declined"`) or 3DS verification is required (`error: "stripe_3ds_required"`).
403Bearer is a `pk_*` API key (scope_required).
503Stripe not configured on this deployment.