curl -X POST 'https://api-sandbox.paywithsoap.com/api/v1/checkouts' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"type": "deposit"
}'
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api-sandbox.paywithsoap.com/api/v1/checkouts')
request = Net::HTTP::Post.new(uri)
request.content_type = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_KEY'
request.body = {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
type: 'deposit'
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.body
const fetch = require('node-fetch');
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
type: 'deposit'
})
};
fetch('https://api-sandbox.paywithsoap.com/api/v1/checkouts', options)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = "https://api-sandbox.paywithsoap.com/api/v1/checkouts"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
}
data = {
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"type": "deposit"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
{
"url": "https://wallet-sandbox.paywithsoap.com?clientSecret=HMC3VTosbzJd7cLsoP3geC5QmSz8jqF6",
"id": "chk_HBq6ExeoRDMPFCCabR8n1h7S1towds7K",
"client_secret": "HMC3VTosbzJd7cLsoP3geC5QmSz8jqF6",
"line_items": [],
"line_items_total_amount_cents": null,
"balance_amount_cents": null,
"type": "deposit",
"fixed_amount_cents": null,
"experience": null,
"payment_options": null
}
Create Checkout
Create a checkout session with POST /api/v1/checkouts. The type is either deposit or withdrawal; purchases and subscriptions are deposits carrying line_items. Returns the checkout url the customer completes payment at.
curl -X POST 'https://api-sandbox.paywithsoap.com/api/v1/checkouts' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"type": "deposit"
}'
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api-sandbox.paywithsoap.com/api/v1/checkouts')
request = Net::HTTP::Post.new(uri)
request.content_type = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_KEY'
request.body = {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
type: 'deposit'
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.body
const fetch = require('node-fetch');
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
type: 'deposit'
})
};
fetch('https://api-sandbox.paywithsoap.com/api/v1/checkouts', options)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = "https://api-sandbox.paywithsoap.com/api/v1/checkouts"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
}
data = {
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"type": "deposit"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
{
"url": "https://wallet-sandbox.paywithsoap.com?clientSecret=HMC3VTosbzJd7cLsoP3geC5QmSz8jqF6",
"id": "chk_HBq6ExeoRDMPFCCabR8n1h7S1towds7K",
"client_secret": "HMC3VTosbzJd7cLsoP3geC5QmSz8jqF6",
"line_items": [],
"line_items_total_amount_cents": null,
"balance_amount_cents": null,
"type": "deposit",
"fixed_amount_cents": null,
"experience": null,
"payment_options": null
}
Authorization header:
Authorization: Bearer YOUR_API_KEY
key_....
Requests with a missing or invalid API key return 422 — never 401 — with a JSON error field, usually {"error": "API key not found."}. Branch on the status code rather than the message: GET /api/v1/device_pings/latest_geo_check does not yet return the same wording.
Never expose your API key in client-side code — it is server-side only.
The type field accepts exactly two values, "deposit" and "withdrawal". The checkout flows below are built from those two values plus the other parameters — there is no "purchase" or "subscription" value for type.
- A deposit checkout (
type: "deposit") deposits money into a customer’s balance. - A purchase checkout is a deposit that carries
line_items, used to buy a product or service such as credits, sweepstakes coins, or digital goods. - A subscription checkout is a deposit that carries
line_itemsandsubscription_data, for recurring billing. - A withdrawal checkout (
type: "withdrawal") withdraws money from a customer’s balance.
Receive Payments
Draft King's Style Deposit
Preset Amount Deposit
Subscription Checkout
Digital Goods Purchase
Ecomm Purchase
Send Payments
Balance Withdrawal
Preset Amount Withdrawal
Common Parameters
| Parameter | Required | Description |
|---|---|---|
customer_id | Yes | Soap customer ID for the customer starting the checkout. |
type | Yes | Checkout direction. Use "deposit" for deposits, purchases, and subscriptions. Use "withdrawal" for withdrawals. |
line_items | Required for purchase and subscription checkouts | Products included in the checkout. Supports existing product references and inline dynamic products. |
subscription_data | Required for subscription checkouts | Billing cadence for a recurring subscription checkout. Includes interval and interval_count. |
fixed_amount_cents | Required for preset amount flows | Fixed amount in cents for preset deposits or preset withdrawals. Must be at least 1. |
balance_amount_cents | Required for balance withdrawal flows | Customer balance in cents. The customer can withdraw up to this amount. Must be at least 1. |
experience | No | Checkout presentation. Use "web", "webview", or "iframe". Set "iframe" when embedding the checkout in an iframe — required for in-frame Apple Pay. See Embedded Checkout. |
payment_options | No | Subset of your enabled payment methods to offer on this checkout, e.g. ["bank_account", "credit_card"]. See Limiting Payment Methods. |
return_url | No | URL where Soap redirects the customer after checkout completion. When the checkout is embedded in an iframe, this redirect happens inside the frame. |
Line Items and Dynamic Pricing
Useline_items for purchase and subscription checkout flows where Soap should show purchased products and compute the checkout total from product quantities. Line items are not used for balance amount, fixed amount, or withdrawal-only flows.
Each line item can be either:
- An existing product reference with
product_idandquantity. - An inline dynamic product with
name,price_cents, andquantity, plus optionalsku,url, anddedup.
dedup is true, include a stable sku. Soap reuses a matching product for the same business when both sku and price_cents match. If dedup is absent or false, Soap creates a new active product from the inline line item.
Line Item Parameters
| Parameter | Required | Description |
|---|---|---|
line_items[].product_id | Yes for existing products | Soap product ID for an existing product. Use this shape with quantity when the product is already in Soap. |
line_items[].name | Yes for inline products | Product name to create and display in checkout. |
line_items[].price_cents | Yes for inline products | Unit price in cents for the inline product. Must be at least 1. |
line_items[].quantity | Yes | Number of units to purchase. Must be at least 1. |
line_items[].sku | Required when dedup is true | Stable merchant SKU used with price_cents to find an existing product for this business. |
line_items[].url | No | Product image URL shown in checkout where supported. |
line_items[].dedup | No | When true, Soap looks for an existing product for the same business by sku and price_cents before creating a new product. Requires sku. |
Dynamic Purchase Example
{
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"type": "deposit",
"line_items": [
{
"name": "Gold Coins Pack",
"price_cents": 999,
"quantity": 1,
"sku": "gold-coins-1000",
"url": "https://example.com/products/gold-coins.png",
"dedup": true
}
],
"experience": "web",
"return_url": "https://myapp.com/store"
}
Limiting Payment Methods
By default a checkout offers every payment method enabled on your account for that checkout type. Passpayment_options to offer only a subset:
{
"customer_id": "cus_123",
"type": "deposit",
"fixed_amount_cents": 5000,
"payment_options": ["bank_account", "credit_card"]
}
credit_card, bank_account, apple_pay, google_pay, link_money, aeropay, glide.
- Saved payment methods of an excluded type are hidden for that checkout.
- When Apple Pay is the only option and the device supports it, the checkout opens with Apple Pay selected.
- The response echoes
payment_options, ornullwhen omitted, like every other unset optional field. - Every listed method must be enabled on your account for the checkout
type. Otherwise Soap responds422:
{
"error": "Unsupported payment_options: google_pay.",
"hint": "Payment methods enabled for deposit checkouts on this account: credit_card, bank_account."
}
Subscription Checkouts
Create a subscription checkout by sendingsubscription_data on POST /api/v1/checkouts. Subscription checkouts are deposit-only and require line_items.
Subscription checkouts use the same line item formats as purchase checkouts: either existing products by product_id or inline dynamic products with name, price_cents, and quantity.
The subscription_data.interval value can be day, week, month, or year. For quarterly billing, use interval: "month" and interval_count: 3.
Subscription Parameters
| Parameter | Required | Description |
|---|---|---|
subscription_data.interval | Yes | Billing interval. Must be day, week, month, or year. |
subscription_data.interval_count | Yes | Number of intervals between charges. Use interval: "month" and interval_count: 3 for quarterly billing. |
{
"customer_id": "cus_aaN5GMMF8CFpsYMuEnN9DPFMtGQaVDQZ",
"type": "deposit",
"line_items": [
{
"name": "Premium Monthly Plan",
"price_cents": 2999,
"quantity": 1,
"sku": "PREMIUM-MONTHLY",
"url": "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?auto=format&fit=crop&w=800&q=80",
"dedup": true
}
],
"subscription_data": {
"interval": "month",
"interval_count": 1
}
}
curl -X POST 'https://api-sandbox.paywithsoap.com/api/v1/checkouts' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"type": "deposit"
}'
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api-sandbox.paywithsoap.com/api/v1/checkouts')
request = Net::HTTP::Post.new(uri)
request.content_type = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_KEY'
request.body = {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
type: 'deposit'
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.body
const fetch = require('node-fetch');
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
type: 'deposit'
})
};
fetch('https://api-sandbox.paywithsoap.com/api/v1/checkouts', options)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = "https://api-sandbox.paywithsoap.com/api/v1/checkouts"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
}
data = {
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"type": "deposit"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
{
"url": "https://wallet-sandbox.paywithsoap.com?clientSecret=HMC3VTosbzJd7cLsoP3geC5QmSz8jqF6",
"id": "chk_HBq6ExeoRDMPFCCabR8n1h7S1towds7K",
"client_secret": "HMC3VTosbzJd7cLsoP3geC5QmSz8jqF6",
"line_items": [],
"line_items_total_amount_cents": null,
"balance_amount_cents": null,
"type": "deposit",
"fixed_amount_cents": null,
"experience": null,
"payment_options": null
}
url, or embed it in an <iframe allow="payment"> to render checkout in context. See Embedded Checkout.subscription is only present when you created a subscription checkout. It is
omitted from the response entirely otherwise, rather than returned as null,
so check whether the key exists instead of comparing it to null. This differs
from checkout webhook payloads, where data.subscription is always present
and is null for non-subscription checkouts.Authorizations
Bearer token authentication using your API key (key_...). Used for every endpoint except POST /api/v1/device_pings.
Body
- Deposit
- Fixed Deposit
- Purchase
- Subscription Checkout
- Withdrawal
- Fixed Withdrawal
Exactly one of the shapes below applies. Deposits take neither amount field (the customer picks the amount), fixed_amount_cents, or line_items (never both, never balance_amount_cents); withdrawals take either balance_amount_cents or fixed_amount_cents (never both, never line_items). Unknown fields are rejected.
Unique identifier for the customer
1"cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870"
Type of transaction - deposit
deposit "deposit"
The experience type for the checkout flow. Use "iframe" when embedding the checkout in an iframe.
web, webview, iframe Subset of the payment methods enabled on your account to offer on this checkout. Every listed method must be enabled for this checkout type; otherwise the request fails with 422. Omit to offer all enabled methods.
1credit_card, bank_account, apple_pay, google_pay, link_money, aeropay, glide ["bank_account", "credit_card"]
URL to redirect the customer after completion (if you are opening a new tab or window for your customer you do not need this)
"https://myapp.com/game/:id"
Response
Use the url field in the response. In web, you can redirect or open a new tab. In native, you can use a WebView.
The url of the checkout experience
Unique identifier for the checkout
Secret used for client-side checkout processing
Line items contained in the checkout (non-empty only for purchases)
Show child attributes
Show child attributes
Total amount in cents for all line items
The available balance passed on creation for a withdrawal, or null. It caps the amount the customer can pick; it is not the amount withdrawn.
Type of checkout transaction
deposit, withdrawal The fixed amount passed on creation, or null. Always present. Mutually exclusive with line_items (deposits) and balance_amount_cents (withdrawals).
The experience passed on creation, or null when omitted.
web, webview, iframe The payment_options passed on creation, or null when omitted (all enabled methods are offered).
["bank_account", "credit_card"]
Subscription metadata. This key is omitted entirely for non-subscription checkouts rather than being returned as null, so check for its presence rather than comparing it to null.
Show child attributes
Show child attributes

