curl --request POST \
--url https://api.beta.suby.fi/v3/payments \
--header 'Content-Type: application/json' \
--header 'X-Suby-Api-Key: <api-key>' \
--data '
{
"productId": "pro_abc123",
"priceCents": "1999",
"customer": {
"id": "cus_abc123",
"email": "jsmith@example.com",
"firstName": "<string>",
"lastName": "<string>"
},
"currency": "<string>",
"displayName": "<string>",
"displayDescription": "<string>",
"displayImageUrl": "<string>",
"billingAddress": {
"line1": "<string>",
"line2": "<string>",
"city": "<string>",
"state": "<string>",
"postalCode": "<string>",
"country": "<string>"
},
"businessData": {
"purchaseAsBusiness": true,
"businessName": "<string>",
"taxId": "<string>"
},
"customerPaymentMethodId": "pi_abc123",
"offSession": false,
"externalRef": "<string>",
"metadata": {}
}
'import requests
url = "https://api.beta.suby.fi/v3/payments"
payload = {
"productId": "pro_abc123",
"priceCents": "1999",
"customer": {
"id": "cus_abc123",
"email": "jsmith@example.com",
"firstName": "<string>",
"lastName": "<string>"
},
"currency": "<string>",
"displayName": "<string>",
"displayDescription": "<string>",
"displayImageUrl": "<string>",
"billingAddress": {
"line1": "<string>",
"line2": "<string>",
"city": "<string>",
"state": "<string>",
"postalCode": "<string>",
"country": "<string>"
},
"businessData": {
"purchaseAsBusiness": True,
"businessName": "<string>",
"taxId": "<string>"
},
"customerPaymentMethodId": "pi_abc123",
"offSession": False,
"externalRef": "<string>",
"metadata": {}
}
headers = {
"X-Suby-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Suby-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
productId: 'pro_abc123',
priceCents: '1999',
customer: {
id: 'cus_abc123',
email: 'jsmith@example.com',
firstName: '<string>',
lastName: '<string>'
},
currency: '<string>',
displayName: '<string>',
displayDescription: '<string>',
displayImageUrl: '<string>',
billingAddress: {
line1: '<string>',
line2: '<string>',
city: '<string>',
state: '<string>',
postalCode: '<string>',
country: '<string>'
},
businessData: {purchaseAsBusiness: true, businessName: '<string>', taxId: '<string>'},
customerPaymentMethodId: 'pi_abc123',
offSession: false,
externalRef: '<string>',
metadata: {}
})
};
fetch('https://api.beta.suby.fi/v3/payments', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.beta.suby.fi/v3/payments",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'productId' => 'pro_abc123',
'priceCents' => '1999',
'customer' => [
'id' => 'cus_abc123',
'email' => 'jsmith@example.com',
'firstName' => '<string>',
'lastName' => '<string>'
],
'currency' => '<string>',
'displayName' => '<string>',
'displayDescription' => '<string>',
'displayImageUrl' => '<string>',
'billingAddress' => [
'line1' => '<string>',
'line2' => '<string>',
'city' => '<string>',
'state' => '<string>',
'postalCode' => '<string>',
'country' => '<string>'
],
'businessData' => [
'purchaseAsBusiness' => true,
'businessName' => '<string>',
'taxId' => '<string>'
],
'customerPaymentMethodId' => 'pi_abc123',
'offSession' => false,
'externalRef' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Suby-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.beta.suby.fi/v3/payments"
payload := strings.NewReader("{\n \"productId\": \"pro_abc123\",\n \"priceCents\": \"1999\",\n \"customer\": {\n \"id\": \"cus_abc123\",\n \"email\": \"jsmith@example.com\",\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"displayName\": \"<string>\",\n \"displayDescription\": \"<string>\",\n \"displayImageUrl\": \"<string>\",\n \"billingAddress\": {\n \"line1\": \"<string>\",\n \"line2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postalCode\": \"<string>\",\n \"country\": \"<string>\"\n },\n \"businessData\": {\n \"purchaseAsBusiness\": true,\n \"businessName\": \"<string>\",\n \"taxId\": \"<string>\"\n },\n \"customerPaymentMethodId\": \"pi_abc123\",\n \"offSession\": false,\n \"externalRef\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Suby-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.beta.suby.fi/v3/payments")
.header("X-Suby-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"productId\": \"pro_abc123\",\n \"priceCents\": \"1999\",\n \"customer\": {\n \"id\": \"cus_abc123\",\n \"email\": \"jsmith@example.com\",\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"displayName\": \"<string>\",\n \"displayDescription\": \"<string>\",\n \"displayImageUrl\": \"<string>\",\n \"billingAddress\": {\n \"line1\": \"<string>\",\n \"line2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postalCode\": \"<string>\",\n \"country\": \"<string>\"\n },\n \"businessData\": {\n \"purchaseAsBusiness\": true,\n \"businessName\": \"<string>\",\n \"taxId\": \"<string>\"\n },\n \"customerPaymentMethodId\": \"pi_abc123\",\n \"offSession\": false,\n \"externalRef\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.beta.suby.fi/v3/payments")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Suby-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"productId\": \"pro_abc123\",\n \"priceCents\": \"1999\",\n \"customer\": {\n \"id\": \"cus_abc123\",\n \"email\": \"jsmith@example.com\",\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"displayName\": \"<string>\",\n \"displayDescription\": \"<string>\",\n \"displayImageUrl\": \"<string>\",\n \"billingAddress\": {\n \"line1\": \"<string>\",\n \"line2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postalCode\": \"<string>\",\n \"country\": \"<string>\"\n },\n \"businessData\": {\n \"purchaseAsBusiness\": true,\n \"businessName\": \"<string>\",\n \"taxId\": \"<string>\"\n },\n \"customerPaymentMethodId\": \"pi_abc123\",\n \"offSession\": false,\n \"externalRef\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"payment": {
"rail": "card",
"id": "pay_abc123",
"organizationId": "<string>",
"customerId": "<string>",
"productId": "<string>",
"subscriptionId": "<string>",
"status": "PENDING",
"paymentMethodCategory": "CARD",
"declineCode": "<string>",
"declineCategory": "SOFT",
"declineAdvice": "TRY_AGAIN_LATER",
"declineNetworkCode": "<string>",
"threeDSecureResult": "AUTHENTICATED",
"displayName": "<string>",
"displayDescription": "<string>",
"displayImageUrl": "<string>",
"priceCents": "<string>",
"currency": "<string>",
"tokenAmount": "<string>",
"tokenFeeAmount": "<string>",
"quoteFiatAmountCents": 123,
"quoteFiatCurrency": "<string>",
"grossAmountCents": 123,
"platformFeeCents": 123,
"merchantNetCents": 123,
"vatAmountCents": 123,
"vatRateBps": 123,
"taxInclusive": true,
"fxSurchargeCents": 123,
"internationalCardSurchargeCents": 123,
"rollingReserveCents": 123,
"refundedAmountCents": 123,
"refundedAt": "2023-11-07T05:31:56Z",
"cryptoSettlementMode": "<string>",
"settlementChainId": 123,
"settlementAsset": "<string>",
"settlementRecipient": "<string>",
"depositAddress": "<string>",
"settlementTxHash": "<string>",
"lifiTxHash": "<string>",
"lifiSubstatus": "<string>",
"successUrl": "<string>",
"cancelUrl": "<string>",
"externalRef": "<string>",
"paymentReceivedAt": "2023-11-07T05:31:56Z",
"paymentSettledAt": "2023-11-07T05:31:56Z",
"paymentConfirmedAt": "2023-11-07T05:31:56Z",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"expiresAt": "2023-11-07T05:31:56Z",
"statusTimeline": [
{
"status": "PENDING",
"at": "2023-11-07T05:31:56Z"
}
],
"items": [
{
"productId": "<string>",
"name": "<string>",
"quantity": 123,
"unitPriceCents": 123
}
],
"asset": {
"chainId": 123,
"chainName": "<string>",
"chainLogoUrl": "<string>",
"symbol": "<string>",
"decimals": 123,
"address": "<string>",
"logoUrl": "<string>"
},
"settlementChain": {
"chainId": 123,
"name": "<string>",
"logoUrl": "<string>"
},
"deposit": {
"expected": "<string>",
"received": "<string>",
"remaining": "<string>",
"confirmations": {
"observed": 123,
"required": 123,
"detectedAt": "2023-11-07T05:31:56Z"
},
"warnings": [
{
"code": "INSUFFICIENT_DEPOSIT_AMOUNT",
"message": "<string>",
"data": {}
}
]
}
},
"checkout": {
"providerPaymentId": "<string>",
"redirectUrl": "<string>",
"threeDsChallengeUrl": "<string>",
"clientSecret": "<string>"
},
"instruction": {
"kind": "qr_deposit",
"chainId": 123,
"depositAddress": "<string>",
"expectedAmount": "<string>",
"decimals": 123,
"symbol": "<string>",
"address": "<string>",
"bip21Uri": "<string>",
"surchargeNote": "<string>"
}
},
"message": "<string>"
}{
"success": false,
"error": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}{
"success": false,
"error": "NOT_FOUND",
"message": "Resource not found"
}{
"success": false,
"error": "VALIDATION_ERROR",
"message": "Validation failed",
"data": {
"fieldErrors": [
{
"field": "method",
"message": "method is a required field"
}
]
}
}{
"success": false,
"error": "RATE_LIMITED",
"message": "Too many requests"
}Debit a stored card, off-session
One shape. Crypto moved to POST /v3/crypto/charges, whose mechanics share
almost nothing with a card debit.
Off-session debit · charge an instrument already stored here:
offSession: true, customer.id, and the pi_… from
GET /v3/customers/{id}/payment-methods. This is the pay-as-you-go path:
metered billing, account top-ups, a threshold crossed.
It always names a per-use product. productId (a product created with
billingMode: pay_as_you_go) and priceCents are both required: the
product says what was consumed, the amount says how much. This is the exact
mirror of mode=setup on a checkout session, which refuses a priced product
for the same reason · the card was stored to be debited per use, so what it
is debited for is a per-use product. A onetime or subscription product
answers 422 PRODUCT_NOT_PRICED_PER_USE.
A card charge with the buyer present is refused. Collecting a card needs a page that renders card fields, and that page is ours · open a checkout session instead. There is no way to hand this endpoint a card token.
curl --request POST \
--url https://api.beta.suby.fi/v3/payments \
--header 'Content-Type: application/json' \
--header 'X-Suby-Api-Key: <api-key>' \
--data '
{
"productId": "pro_abc123",
"priceCents": "1999",
"customer": {
"id": "cus_abc123",
"email": "jsmith@example.com",
"firstName": "<string>",
"lastName": "<string>"
},
"currency": "<string>",
"displayName": "<string>",
"displayDescription": "<string>",
"displayImageUrl": "<string>",
"billingAddress": {
"line1": "<string>",
"line2": "<string>",
"city": "<string>",
"state": "<string>",
"postalCode": "<string>",
"country": "<string>"
},
"businessData": {
"purchaseAsBusiness": true,
"businessName": "<string>",
"taxId": "<string>"
},
"customerPaymentMethodId": "pi_abc123",
"offSession": false,
"externalRef": "<string>",
"metadata": {}
}
'import requests
url = "https://api.beta.suby.fi/v3/payments"
payload = {
"productId": "pro_abc123",
"priceCents": "1999",
"customer": {
"id": "cus_abc123",
"email": "jsmith@example.com",
"firstName": "<string>",
"lastName": "<string>"
},
"currency": "<string>",
"displayName": "<string>",
"displayDescription": "<string>",
"displayImageUrl": "<string>",
"billingAddress": {
"line1": "<string>",
"line2": "<string>",
"city": "<string>",
"state": "<string>",
"postalCode": "<string>",
"country": "<string>"
},
"businessData": {
"purchaseAsBusiness": True,
"businessName": "<string>",
"taxId": "<string>"
},
"customerPaymentMethodId": "pi_abc123",
"offSession": False,
"externalRef": "<string>",
"metadata": {}
}
headers = {
"X-Suby-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Suby-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
productId: 'pro_abc123',
priceCents: '1999',
customer: {
id: 'cus_abc123',
email: 'jsmith@example.com',
firstName: '<string>',
lastName: '<string>'
},
currency: '<string>',
displayName: '<string>',
displayDescription: '<string>',
displayImageUrl: '<string>',
billingAddress: {
line1: '<string>',
line2: '<string>',
city: '<string>',
state: '<string>',
postalCode: '<string>',
country: '<string>'
},
businessData: {purchaseAsBusiness: true, businessName: '<string>', taxId: '<string>'},
customerPaymentMethodId: 'pi_abc123',
offSession: false,
externalRef: '<string>',
metadata: {}
})
};
fetch('https://api.beta.suby.fi/v3/payments', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.beta.suby.fi/v3/payments",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'productId' => 'pro_abc123',
'priceCents' => '1999',
'customer' => [
'id' => 'cus_abc123',
'email' => 'jsmith@example.com',
'firstName' => '<string>',
'lastName' => '<string>'
],
'currency' => '<string>',
'displayName' => '<string>',
'displayDescription' => '<string>',
'displayImageUrl' => '<string>',
'billingAddress' => [
'line1' => '<string>',
'line2' => '<string>',
'city' => '<string>',
'state' => '<string>',
'postalCode' => '<string>',
'country' => '<string>'
],
'businessData' => [
'purchaseAsBusiness' => true,
'businessName' => '<string>',
'taxId' => '<string>'
],
'customerPaymentMethodId' => 'pi_abc123',
'offSession' => false,
'externalRef' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Suby-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.beta.suby.fi/v3/payments"
payload := strings.NewReader("{\n \"productId\": \"pro_abc123\",\n \"priceCents\": \"1999\",\n \"customer\": {\n \"id\": \"cus_abc123\",\n \"email\": \"jsmith@example.com\",\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"displayName\": \"<string>\",\n \"displayDescription\": \"<string>\",\n \"displayImageUrl\": \"<string>\",\n \"billingAddress\": {\n \"line1\": \"<string>\",\n \"line2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postalCode\": \"<string>\",\n \"country\": \"<string>\"\n },\n \"businessData\": {\n \"purchaseAsBusiness\": true,\n \"businessName\": \"<string>\",\n \"taxId\": \"<string>\"\n },\n \"customerPaymentMethodId\": \"pi_abc123\",\n \"offSession\": false,\n \"externalRef\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Suby-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.beta.suby.fi/v3/payments")
.header("X-Suby-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"productId\": \"pro_abc123\",\n \"priceCents\": \"1999\",\n \"customer\": {\n \"id\": \"cus_abc123\",\n \"email\": \"jsmith@example.com\",\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"displayName\": \"<string>\",\n \"displayDescription\": \"<string>\",\n \"displayImageUrl\": \"<string>\",\n \"billingAddress\": {\n \"line1\": \"<string>\",\n \"line2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postalCode\": \"<string>\",\n \"country\": \"<string>\"\n },\n \"businessData\": {\n \"purchaseAsBusiness\": true,\n \"businessName\": \"<string>\",\n \"taxId\": \"<string>\"\n },\n \"customerPaymentMethodId\": \"pi_abc123\",\n \"offSession\": false,\n \"externalRef\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.beta.suby.fi/v3/payments")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Suby-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"productId\": \"pro_abc123\",\n \"priceCents\": \"1999\",\n \"customer\": {\n \"id\": \"cus_abc123\",\n \"email\": \"jsmith@example.com\",\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"displayName\": \"<string>\",\n \"displayDescription\": \"<string>\",\n \"displayImageUrl\": \"<string>\",\n \"billingAddress\": {\n \"line1\": \"<string>\",\n \"line2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postalCode\": \"<string>\",\n \"country\": \"<string>\"\n },\n \"businessData\": {\n \"purchaseAsBusiness\": true,\n \"businessName\": \"<string>\",\n \"taxId\": \"<string>\"\n },\n \"customerPaymentMethodId\": \"pi_abc123\",\n \"offSession\": false,\n \"externalRef\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"payment": {
"rail": "card",
"id": "pay_abc123",
"organizationId": "<string>",
"customerId": "<string>",
"productId": "<string>",
"subscriptionId": "<string>",
"status": "PENDING",
"paymentMethodCategory": "CARD",
"declineCode": "<string>",
"declineCategory": "SOFT",
"declineAdvice": "TRY_AGAIN_LATER",
"declineNetworkCode": "<string>",
"threeDSecureResult": "AUTHENTICATED",
"displayName": "<string>",
"displayDescription": "<string>",
"displayImageUrl": "<string>",
"priceCents": "<string>",
"currency": "<string>",
"tokenAmount": "<string>",
"tokenFeeAmount": "<string>",
"quoteFiatAmountCents": 123,
"quoteFiatCurrency": "<string>",
"grossAmountCents": 123,
"platformFeeCents": 123,
"merchantNetCents": 123,
"vatAmountCents": 123,
"vatRateBps": 123,
"taxInclusive": true,
"fxSurchargeCents": 123,
"internationalCardSurchargeCents": 123,
"rollingReserveCents": 123,
"refundedAmountCents": 123,
"refundedAt": "2023-11-07T05:31:56Z",
"cryptoSettlementMode": "<string>",
"settlementChainId": 123,
"settlementAsset": "<string>",
"settlementRecipient": "<string>",
"depositAddress": "<string>",
"settlementTxHash": "<string>",
"lifiTxHash": "<string>",
"lifiSubstatus": "<string>",
"successUrl": "<string>",
"cancelUrl": "<string>",
"externalRef": "<string>",
"paymentReceivedAt": "2023-11-07T05:31:56Z",
"paymentSettledAt": "2023-11-07T05:31:56Z",
"paymentConfirmedAt": "2023-11-07T05:31:56Z",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"expiresAt": "2023-11-07T05:31:56Z",
"statusTimeline": [
{
"status": "PENDING",
"at": "2023-11-07T05:31:56Z"
}
],
"items": [
{
"productId": "<string>",
"name": "<string>",
"quantity": 123,
"unitPriceCents": 123
}
],
"asset": {
"chainId": 123,
"chainName": "<string>",
"chainLogoUrl": "<string>",
"symbol": "<string>",
"decimals": 123,
"address": "<string>",
"logoUrl": "<string>"
},
"settlementChain": {
"chainId": 123,
"name": "<string>",
"logoUrl": "<string>"
},
"deposit": {
"expected": "<string>",
"received": "<string>",
"remaining": "<string>",
"confirmations": {
"observed": 123,
"required": 123,
"detectedAt": "2023-11-07T05:31:56Z"
},
"warnings": [
{
"code": "INSUFFICIENT_DEPOSIT_AMOUNT",
"message": "<string>",
"data": {}
}
]
}
},
"checkout": {
"providerPaymentId": "<string>",
"redirectUrl": "<string>",
"threeDsChallengeUrl": "<string>",
"clientSecret": "<string>"
},
"instruction": {
"kind": "qr_deposit",
"chainId": 123,
"depositAddress": "<string>",
"expectedAmount": "<string>",
"decimals": 123,
"symbol": "<string>",
"address": "<string>",
"bip21Uri": "<string>",
"surchargeNote": "<string>"
}
},
"message": "<string>"
}{
"success": false,
"error": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}{
"success": false,
"error": "NOT_FOUND",
"message": "Resource not found"
}{
"success": false,
"error": "VALIDATION_ERROR",
"message": "Validation failed",
"data": {
"fieldErrors": [
{
"field": "method",
"message": "method is a required field"
}
]
}
}{
"success": false,
"error": "RATE_LIMITED",
"message": "Too many requests"
}Authorizations
Secret API key. sk_live_… (production) or sk_sandbox_… (sandbox).
Headers
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.
255"5f3b9c2e-1a4d-4f2b-9c31-7e2a1b6d8c04"
Body
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.
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.
"pro_abc123"
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.
^[1-9]\d*$"1999"
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.
Show child attributes
Show child attributes
CARD, APPLE_PAY, GOOGLE_PAY, KLARNA, IDEAL, BANCONTACT, TWINT, BLIK, AFFIRM, ALMA, BILLIE, SCALAPAY, MULTIBANCO, PAYPAL, SEPA_DIRECT_DEBIT, ACH_DIRECT_DEBIT, CRYPTO 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.
^[A-Z]{3}$Label snapshotted on the Payment · what the payer reads on the receipt for this period ("April usage"). Falls back to the product name.
200500MoR 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.
inclusive, exclusive Required by the PSP when the stored customer has none (acquirers reject an empty country).
Show child attributes
Show child attributes
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.
Show child attributes
Show child attributes
The stored instrument to debit (pi_…, from GET /v3/customers/{id}/payment-methods). Required when offSession=true.
"pi_abc123"
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.
Your reference, stored on the Payment for reconciliation.
120Key-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.
Show child attributes
Show child attributes
Was this page helpful?

