Skip to content
OpenRelay is in early access, and the /v1 API is stable. New capabilities ship in the changelog.
API ReferenceBilling and usageBilling

Charge the saved card to top up prepaid balance

Charges the org's default saved card off-session for amountCents and returns the PaymentIntent id and status, which tells the client what to do next. The balance credit is applied by the payment_intent.succeeded webhook (the authoritative money signal), not this response: poll the balance after success.

Required permission

Requires the billing.manage permission. See Permissions for the roles and API key permissions that include it.

Command line

The orl CLI wraps this endpoint:

orl billing deposit create --amount-cents <amount-cents>
POST
/v1/orgs/{orgId}/billing/deposit

Authorization

apiKey
headerAuthorizationBearer <token>

OpenRelay API key. Send it as Authorization: Bearer or_… (legacy vl_… keys still work).

Path Parameters

orgId*string

Request Body

application/json
  1. body
amountCents*integer

Amount to charge the saved card, in cents. The flat floor is $25 and the default per-deposit cap is $500 (raised to an approved monthly spend limit). While the org has usage running the endpoint requires at least one hour of the current burn; read the exact figure from Balance.minDepositCents rather than re-deriving it.

Range2500 <= value
idempotencyKey?string

Client-generated id for this logical deposit; reused verbatim on retry so a network/client retry can't double-charge. Optional: the server generates one if absent (then retries won't dedupe).

deviceFingerprint?string

Optional Fingerprint visitor id (see DeviceSignals). Recorded and clustered. A device that puts the account on a verification hold gets 403 ACCOUNT_PENDING_VERIFICATION, or 403 VERIFICATION_UNAVAILABLE when the hold could not be recorded; every other verdict is observe-only.

Lengthlength <= 128
deviceEventId?string

Optional Fingerprint event id (see DeviceSignals).

Lengthlength <= 128

Response Body

Charge outcome (status drives the dashboard's next step)

application/json
  1. response
paymentIntentId*string
status*string

Stripe PaymentIntent status. "succeeded" → credit lands via webhook; "requires_action" → complete SCA on-session with clientSecret; "requires_payment_method" → the card was declined.

declineCode?string

Why the card was declined, set when status is requires_payment_method and Stripe gave a reason: a Stripe decline code (https://docs.stripe.com/declines/codes) such as insufficient_funds, expired_card, incorrect_cvc or card_velocity_exceeded. A decline Stripe asks merchants not to explain (fraudulent, lost_card, stolen_card, merchant_blacklist) is reported as generic_decline. New codes can appear, so treat an unknown one as a generic decline.

clientSecret?string

Set only when status is requires_action (on-session SCA).

publishableKey?string

Set with clientSecret: the Stripe publishable key Stripe.js needs to confirm the PaymentIntent on-session.

Example Request
curl -X POST 'https://api.openrelay.inc/v1/orgs/string/billing/deposit' \  -H 'Content-Type: application/json' \  -d '{  "amountCents": 5000,  "idempotencyKey": "dep-2026-07-02-a1b2c3"}'
Example Response
{  "paymentIntentId": "string",  "status": "string",  "declineCode": "string",  "clientSecret": "string",  "publishableKey": "string"}