Charges
Create charges against cards and tokens.
You can pass customer_id to charge a vaulted card, payment_token for a one-time charge, or both (token is used for the charge, customer is linked to the transaction). Specify the charge amount using one of three modes: a direct amount, a product_id, or line_items. These are mutually exclusive.
Create Charge
Create a charge. Accepts a saved customer card, a payment token, or an Apple Pay / Google Pay payload (paysio_wallet). Returns 402 if declined.
https://paysio.com/api/v1/chargesAuthorizations
Secret key (sk_*). Prepend your key with Bearer, e.g. Bearer sk_test_your_secret_key.
Body
Customer ID — charges their saved card on file if no payment_token is provided. On NMI and Debit & Payouts this is served automatically by the Paysio vault; pass payment_method_id to target a specific saved card.
One-time card token from paysio.createToken()
An Apple Pay / Google Pay payload from the paysio.js walletPayment event (data.paysioWallet), forwarded VERBATIM. Paysio decrypts the wallet token server-side and charges it on your card gateway. Shape: { type, apple_payment_data? | google_token?, info? }. Cannot combine with payment_token, gateway, rail "ach", or 3DS fields — wallet credentials carry their own authentication. Single-use and short-lived: charge immediately, never store. See the Wallets guide.
Customer email. When passed without customer_id, the customer is found or created automatically and the charge is linked to it (required so Debit & Payouts charges work without a separate /customers call).
Vault the card to the customer in this same call, then charge the saved instrument. Does the processor-correct vault once (never reuses a single-use token). Requires customer_id or email.
Settle an existing invoice with this charge instead of emailing a payment link and waiting. On approval the invoice is marked paid — or "processing" on a rail that settles later, flipping to paid when it clears — and its payment link is closed so it cannot be paid twice. amount must equal the invoice total exactly; an invoice already paid, processing or void is refused with 409. The response carries invoice_id and invoice_status. To bill a saved card AND send the document, create the invoice as a draft (no send), charge it here, then POST /invoices/:id/send — in that order the email is a receipt (says paid, button opens the invoice) instead of a "Pay Invoice" mail for money you just took. On Debit & Payouts the charge answers "processing", not paid: send is refused in that window, so wait for the invoice to reach paid and send the receipt then. On NMI/Stripe an approval is final, so you can send immediately.
Used when creating the customer inline (with email)
Used when creating the customer inline (with email)
Used when creating the customer inline (with email)
Strongly recommended on EVERY card charge — not just the first, and not only when creating a customer inline. The address is stored on the saved card and reused for AVS on later charges and renewals. Most importantly, paying money back OUT to that card (refund to card, payout link, disbursement) requires a billing postal code: a card saved without one fails later with "No billing ZIP on file for this recipient". Passing the address to your 3DS call is not a substitute — 3DS data is consumed by the issuer and never stored. On Debit & Payouts send a complete, valid US address (billing_country "US"); a mismatch is rejected with "Request validation failed".
Amount in cents (e.g., 2999 for $29.99). Required if product_id and line_items are not provided.
Currency code (default: USD)
Description for this charge (only with amount mode)
Charge based on an existing product's price. Only one_time products. Mutually exclusive with amount and line_items.
Quantity when using product_id (default: 1)
Array of items to charge. Each item: { product_id, quantity?, unit_price? } or { name, amount, quantity? }. unit_price (cents) bills the line at that rate instead of the catalog price (required for open_ended products). Mutually exclusive with amount and product_id.
Make this charge an add-on to an earlier transaction in the same workspace, currency and mode. The charge stays its own transaction (the money moved separately) but not its own order: it inherits the parent's shipping address, the Orders view folds it under the parent, a fulfillment on the parent can ship its items, and the parent's fulfillment status counts them. Returned as parent_transaction_id on both the transaction and the payment.completed event.
Stripe-gateway wallets only: "apple_pay" or "google_pay", sent alongside the pm_ payment_token from Stripe's wallet flow. Never needed with paysio_wallet — the type is inside the payload.
The wallet payer contact from the paysio.js walletPayment event (data.wallet: payerEmail, billingInfo, shippingInfo). Forward it so Apple Pay / Google Pay charges create/link a customer; the sheet's billingInfo address feeds AVS, the transaction, the customer, and any vaulted card (explicit billing_* body fields win), and shippingInfo is stored on the transaction's shipping fields — matching hosted checkout. Without it (and without email), the charge succeeds but has no customer attached.
Arbitrary key-value metadata to attach to the transaction
Optional per-request gateway override for a NEW-card charge: "nmi", "paysio", "stripe", or "aptpay" (Paysio Debit & Payouts). Omit to use the workspace default. Must be configured (else 400). A saved customer/method stays locked to its own gateway — a conflicting value returns 400. Passing this also disables Smart Routing for the request.
Card security code. Debit & Payouts workspaces: required only when charging a saved card (vault charge). Never pass it with payment_token — the token already carries the CVC collected by the secure fields. Never stored.
"card" (default) or "ach" to debit a bank account. ACH works on Paysio Debit & Payouts or NMI workspaces, routed by the workspace bank processor.
Charge a specific saved payment method (card or bank account) instead of the default. To 3D-Secure a saved card, pass this SAME id to POST /three-ds/authenticate first, then send the result back here as three_ds.
With rail "ach": 9-digit routing number for an inline bank debit
With rail "ach": bank account number (4-17 digits)
With rail "ach": "checking" (default) or "saving" (only used by NMI)
With rail "ach": "personal" (default) or "business" (NMI eCheck only; ignored by Debit & Payouts)
Instant ACH (Open Banking) opt-in, Debit & Payouts only. Http(s) URL on YOUR site (max 255 chars) where the payer lands after completing the hosted bank authorization. With the workspace "Instant bank debits" setting on, the debit attempts the instant rail; a first-time payer gets bank_auth_url in the response. Omit for standard ACH.
Debit & Payouts only: idempotency key — reusing one returns 409 instead of charging twice
The COMPLETE threeDS.authenticate() (or /three-ds/finish) result, passed through verbatim: { status, eci, authenticationValue, dsTransId, threeDSServerTransID, threeDsVersion }. REQUIRED on every charge you want authenticated, INCLUDING charges against a saved payment_method_id — nothing is attached automatically, and a charge sent without it authorizes with no liability shift and records no 3DS data. Send every field you received; Paysio forwards exactly what the routed acquirer needs, so filtering by gateway yourself can silently drop the liability shift.
Flat alternative to three_ds.status ("Y", "A", "U", ...). Flat fields take precedence over the object; if you use them, map every one.
Flat alternative to three_ds.eci
Flat alternative to three_ds.authenticationValue
Flat alternative to three_ds.dsTransId (DS Transaction ID)
Flat alternative to three_ds.threeDSServerTransID
Flat alternative to three_ds.threeDsVersion (e.g. "2.2.0")
Optional "verified" / "attempted" hint; derived from the status when omitted
Send the Paysio receipt email to the buyer. Default true. Set false to send your own — nothing else changes.
Smart Routing
With Smart Routing enabled for your workspace, Paysio classifies the card before picking a gateway: debit and prepaid cards go to Paysio Debit & Payouts (the cheaper debit rail), credit cards go to your NMI-family gateway. It happens server-side on the same POST /charges call — nothing changes in your request, and the processorType on the response tells you where it landed. Classification is cached per BIN, so repeat charges on the same card range add no latency.
Routing applies when all of these hold:
- Smart Routing is on for the workspace (Settings → Checkout).
- The charge uses a fresh
payment_tokenfrompaysio.createToken(). Wallet payments (paysio_wallet) always settle on the workspace's wallet gateway and never smart-route. - No
gatewayoverride is passed — an explicit gateway always wins. - No saved method is used (
customer_id,payment_method_id,vault_payment_method_id) — see the caveat below. billing_countryis"US". Any other country skips classification and uses your default gateway, so always send it on card charges.
Saved cards are not re-classified
A charge against a saved/vaulted method runs on your workspace's default card gateway. If that default is Paysio Debit & Payouts and the saved card is a credit card, the debit rail declines it — charge credit cards on an NMI-family gateway, or pass gateway explicitly on that request. Routing never changes the amount, the response shape, or how you handle webhooks.
One call, any gateway
The same request works on NMI, Stripe, and Paysio Debit & Payouts. Tokenize on the client with paysio.createToken(), then send the token plus the customer's email to POST /charges. Paysio resolves or creates the customer, vaults the card on the correct processor, and charges it — you never reuse a single-use token or branch your code per gateway. When the workspace switches processors in the dashboard, this call keeps working unchanged.
// Canonical seamless charge — identical on every processor
{
"email": "[email protected]",
"payment_token": "ptok_...", // from paysio.createToken()
"amount": 2999,
"save_payment_method": true, // vault + charge in one call
// Always send the billing address. It is stored on the saved card,
// reused for AVS on later charges, and REQUIRED to pay money back
// out to this card later (refunds to card, payout links).
"first_name": "Jane",
"last_name": "Doe",
"billing_address_1": "123 Main St",
"billing_city": "Jacksonville",
"billing_state": "FL",
"billing_postal_code": "32204",
"billing_country": "US"
}No cvc field, no gateway branches: the token from paysio.createToken() already carries the CVC the secure fields collected, on every gateway. The cvc body param is only for charging a saved card later on Debit & Payouts (see below). save_payment_method is idempotent — charging the same card again with it simply reuses the saved instrument.
Always send the billing address
The billing address is optional to make a charge succeed, but omitting it causes problems you only discover much later. Send billing_address_1, billing_city, billing_state, billing_postal_code and billing_country on every card charge.
- It is stored on the saved card. The address is persisted to the payment method and reused for AVS on every later charge, including subscription renewals. Omit it and the card is saved with no address — there is no way to recover it from the charge afterwards.
- Payouts to that card will fail without it. Sending money back to a customer's card needs a billing postal code. A card saved without one is rejected at payout time with
No billing ZIP on file for this recipient— long after the charge succeeded. - It improves authorization rates. Issuers decline more often when AVS data is absent.
- Your 3DS call does not count. Billing passed to 3DS authentication is consumed by the issuer and never stored by Paysio. Only the address on
POST /chargesis persisted.
Debit & Payouts behavior
- Asynchronous settlement — charges return
"status": "pending_settlement"; the final state arrives viapayment.completedorpayment.failedwebhooks. - CVC required for vault charges only — pass
cvcwhen charging a saved card (customer_idwithout a fresh token). It is sent to the network and never stored; missing CVC returns 400. Charges with apayment_tokennever need it — the token carries the CVC from the secure fields. - ACH debits — pass
rail: "ach"with a saved bank-accountpayment_method_id, or inlinerouting_number+account_number. No CVC needed. - Instant ACH (Open Banking) — add
return_urlto an ACH charge (with the workspace's Instant bank debits setting on) to attempt the instant rail. A first-time payer getsbank_auth_urlback — send them to that hosted page to sign into their bank and authorize the debit; they return to yourreturn_urlwhen done. The redirect is UX only: settlement still arrives via thepayment.completedwebhook (or poll the charge —bank_auth_statusgoes"awaiting" → "authorized", or"expired"if they never finish within 3 hours and the charge fails). Returning payers get no URL and nothing to do. If the instant rail is unavailable the same request falls back to standard ACH automatically. - US-only, USD-only — non-US cards and other currencies are rejected with 400.
- Send a complete, valid US billing address on every charge — include
billing_address_1,billing_city,billing_state,billing_postal_codeandbilling_country: "US". Debit & Payouts runs strict address/AVS validation and uses the ZIP to resolve card rails. A missing address fails card payouts later; a mismatched one (e.g. a non-US postal code withcountry: "US") is rejected up front withRequest validation failed. Always send the cardholder's real billing address — don't omit it or guess.
// Vault charge with CVC
{ "customer_id": "customer-uuid", "amount": 2999, "cvc": "123" }
// ACH debit from a saved bank account
{ "customer_id": "customer-uuid", "payment_method_id": "instrument-id",
"amount": 2999, "rail": "ach" }
// ACH debit with inline bank details
{ "customer_id": "customer-uuid", "amount": 2999, "rail": "ach",
"routing_number": "021000021", "account_number": "1234567890" }
// Instant ACH (Open Banking) — first payment returns bank_auth_url
{ "customer_id": "customer-uuid", "payment_method_id": "instrument-id",
"amount": 2999, "rail": "ach",
"return_url": "https://yoursite.com/order/complete" }See the Debit & Payouts guide for the full settlement model and sandbox test cards.