Skip to main content
POST
Debit a stored card, off-session

Authorizations

X-Suby-Api-Key
string
header
required

Secret API key. sk_live_… (production) or sk_sandbox_… (sandbox).

Headers

Idempotency-Key
string

Optional key (≤255 chars, e.g. a UUID v4) that makes this POST safe to retry: the first request executes and its response is cached for 24h; a retry with the SAME key replays that response instead of re-executing (no duplicate payment/subscription). A reused key with a different request → 422 IDEMPOTENCY_KEY_CONFLICT; a retry while the first is still in flight → 409. See the Idempotency guide.

Maximum string length: 255
Example:

"5f3b9c2e-1a4d-4f2b-9c31-7e2a1b6d8c04"

Body

application/json

This endpoint charges metered usage, and nothing else. One shape is accepted: an off-session debit (offSession: true with customerPaymentMethodId) of a product created with billingMode: pay_as_you_go. A card charge with the buyer present is refused · collecting a card needs a page that renders card fields, and that page is the hosted checkout (POST /v3/checkout/sessions). Crypto has its own namespace, POST /v3/crypto/charges.

Both halves are required. productId says WHAT was consumed, priceCents says how much. A per-use product carries no price of its own, so neither can be inferred from the other. A product the catalog already prices — onetime or subscription — is refused with PRODUCT_NOT_PRICED_PER_USE: debiting a onetime product off-session bills a customer again for something they authorised once, and a subscription product for a cycle Suby's own clock already bills. Both would succeed at the acquirer, which is why they are refused here.

Every payment is attributed to a customer; there are no anonymous charges.

The metered flow: collect a card once with a mode: "setup" checkout session, then debit it here as usage accrues, one Idempotency-Key per billing period. The product's shared link (/p/{productId}) opens that setup session on its own, so a per-use product is sellable without writing the session call yourself.

productId
string
required

The per-use product this usage belongs to. REQUIRED · it is what puts the charge in the product's revenue and analytics, and what product_id carries on the outbound payment.succeeded. Must be billingMode: pay_as_you_go; anything else answers 422 PRODUCT_NOT_PRICED_PER_USE.

Example:

"pro_abc123"

priceCents
string
required

What was consumed, in minor units, as a string of digits · "1999" = 19.99. REQUIRED · the product carries no price for this call to fall back on. The currency comes from the product.

Pattern: ^[1-9]\d*$
Example:

"1999"

customer
object
required

How a customer is named in a request body: exactly one of id or email. With id the name fields are ignored · the customer already has them on file. With email the customer is created on the fly (email is the get-or-create key). Supplying both, or neither, is a validation error.

method
enum<string>
required
Available options:
CARD,
APPLE_PAY,
GOOGLE_PAY,
KLARNA,
IDEAL,
BANCONTACT,
TWINT,
BLIK,
AFFIRM,
ALMA,
BILLIE,
SCALAPAY,
MULTIBANCO,
PAYPAL,
SEPA_DIRECT_DEBIT,
ACH_DIRECT_DEBIT,
CRYPTO
currency
string

ISO 4217. Optional · the product's own currency is authoritative. Sending a DIFFERENT one answers 422 PRODUCT_CURRENCY_MISMATCH rather than being rebased: the two readings differ by an exchange rate, and one of them debits a real customer the wrong amount.

Pattern: ^[A-Z]{3}$
displayName
string

Label snapshotted on the Payment · what the payer reads on the receipt for this period ("April usage"). Falls back to the product name.

Maximum string length: 200
displayDescription
string | null
Maximum string length: 500
displayImageUrl
string<uri> | null
taxBehavior
enum<string>

MoR VAT: exclusive prices HT and adds VAT on top; inclusive treats the price as VAT-inclusive. Omit it to take the product's own taxBehavior (an ad-hoc amount with no product falls back to exclusive). Ignored when no VAT applies.

Available options:
inclusive,
exclusive
billingAddress
object

Required by the PSP when the stored customer has none (acquirers reject an empty country).

businessData
object

B2B purchase details. Accepted on ALL accounts · businessName / taxId are always stored on the customer, and businessName doubles as the card holder name. The VAT reverse-charge it triggers (0% VAT except France) only takes effect on Merchant-of-Record accounts; on non-MoR accounts no VAT applies at all, so it has no tax effect.

customerPaymentMethodId
string

The stored instrument to debit (pi_…, from GET /v3/customers/{id}/payment-methods). Required when offSession=true.

Example:

"pi_abc123"

offSession
boolean
default:false

Debit a stored instrument with no customer present. Required · it is the only shape this endpoint accepts. Needs customer.id + customerPaymentMethodId. Sent to the card networks as an ON-DEMAND merchant-initiated transaction (the amount and date were not agreed in advance); subscription cycles carry the recurring indicator instead, and neither is settable from this call.

externalRef
string

Your reference, stored on the Payment for reconciliation.

Maximum string length: 120
metadata
object

Key-value pairs. ≤50 keys, keys ≤40 chars, values are strings ≤500 chars (or null to clear). Nested structures must be JSON-stringified into a single string value.

Response

Payment created

success
boolean
required
Example:

true

data
object
required

Endpoint-specific payload.

message
string