Build with TandemPay
Create hosted checkout sessions from your server, redirect customers to pay, and confirm orders from signed webhooks.
Overview
The TandemPay API is organized around checkout sessions and payments. Create sessions from your server, mount checkout in the browser, then use webhooks as the source of truth for payment and settlement state.
Production
https://api.tandempay.io/v1Sandbox
https://api.sandbox.tandempay.io/v1Create a session
Initialize the amount and return URLs on your server.
Redirect to checkout
Send the customer to the hosted checkout URL.
Listen for events
Fulfill orders from signed payment webhooks.
WooCommerce plugin
Merchant accessAdd TandemPay checkout to an existing WooCommerce store without building a custom integration. The plugin handles session creation, order status syncing, and webhook verification.
Available in the merchant dashboard after approval.
Authentication
Authenticate server requests with a secret API key issued in the merchant dashboard after approval. Keys are scoped to one merchant and never expose operator credentials.
Authorization: Bearer tp_live_sk_••••••••••••••••Secret key · server only
Creates checkout sessions, retrieves payments, and lists payment history.
Test vs live
Use tp_test_sk_* in sandbox and tp_live_sk_* in production.
A merchant ID identifies your account; it does not authorize a request. Never expose a secret key in browser code, mobile apps, logs, or source control.
Quickstart
1. Create a checkout session
const response = await fetch(
"https://api.tandempay.io/v1/checkout/sessions",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.TANDEMPAY_SECRET_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({
amount: 114.00,
currency: "USD",
order_id: "order_1842",
customer_email: "customer@example.com",
success_url: "https://yourstore.com/order/success",
cancel_url: "https://yourstore.com/cart"
})
}
);
const session = await response.json();2. Redirect to hosted checkout
window.location.assign(session.checkout_url);3. Confirm fulfillment from a webhook
Wait for payment.succeeded before fulfilling the order. Redirects improve customer experience, but are not a reliable payment confirmation channel.
Checkout sessions
/checkout/sessionsSecret keyCreate a checkout session and receive a hosted checkout URL. Amounts are decimal USD values.
amountnumber · requiredTotal amount in USD (e.g. 114.00).currencystring · optionalPresentment currency. Defaults to USD.order_idstring · optionalYour unique order reference.customer_emailstring · optionalCustomer email for receipts.success_urlURL · requiredReturn URL after successful payment.cancel_urlURL · requiredReturn URL when checkout is canceled.metadataobject · optionalString key-value pairs attached to the payment.{
"id": "clxyz123",
"object": "checkout.session",
"status": "open",
"amount": 114.00,
"currency": "USD",
"reference_id": "tp_a1b2c3d4e5f6",
"checkout_url": "https://checkout.tandempay.io/pay/tp_a1b2c3d4e5f6",
"success_url": "https://yourstore.com/order/success",
"cancel_url": "https://yourstore.com/cart",
"created": 1726128000
}Track payment status
/payments/{reference_id}Secret keyRetrieve payment status by reference ID. Re-fetches provider state when available.
{
"id": "clxyz123",
"object": "payment",
"reference_id": "tp_a1b2c3d4e5f6",
"status": "succeeded",
"provider_status": "FILLED",
"amount": 114.00,
"amount_received": 114.00,
"currency": "USDC",
"network": "BASE",
"customer_email": "customer@example.com",
"order_id": "order_1842",
"created": 1726128000,
"updated": 1726128300
}/payments?limit=20&status=succeededSecret keyList payments with cursor pagination. Filter by status.
openCheckout session created, awaiting payment.processingPayment is being confirmed.partially_paidPartial amount received.succeededPayment completed successfully.overpaidCustomer paid more than requested.cancelledPayment was cancelled.Ticker
/tickerSecret keyNormalized asset prices with 60-second server-side caching.
{
"object": "ticker",
"data": [
{ "blockchain": "BASE", "currency": "USDC", "price_usd": 1.0 }
]
}Webhooks
your-server.com/webhooks/tandempayYour endpointReceive signed payment events. Verify the TandemPay-Signature header before fulfilling orders.
TandemPay-Signature: t=1726128000,v1=5d8f9a...payment.processingPayment is open or partially filled.payment.succeededPayment completed.payment.overpaidCustomer overpaid.payment.cancelledPayment cancelled.Errors and idempotency
Errors use stable machine-readable codes. The request ID is included in both the response body andtandempay-request-id header for support and tracing.
{
"error": {
"type": "invalid_request",
"code": "amount_too_small",
"message": "Amount must be at least 100 usd.",
"param": "amount",
"request_id": "req_01J8YA2B8FQP"
}
}200 / 201The request completed successfully.400Parameters are missing or invalid.401The API key is missing or invalid.402The payment could not be completed.404The requested resource does not exist.409The request conflicts with current resource state.429Too many requests; retry after the supplied delay.5xxA TandemPay service error occurred; retry safely.Send a unique Idempotency-Key with every POST request. Reusing the key with the same payload returns the original response; reusing it with different parameters returns HTTP 409.
Developer support
Need help integrating?
Send your request ID, environment, and a sanitized request example. Never email secret keys or raw card data.
contact@tandempay.io