Developer docs

Hosted checkout, WooCommerce plugin, checkout session API and webhooks. Base URL: https://api.swtchpay.com. Every endpoint, field and error is in the API reference.

How the hosted checkout works

Every payment starts with a checkout session that you create from your server. We return a checkout_url. Send the shopper there (redirect, new tab, or an iframe on your own page). The rest happens on our page:

  1. The shopper sees your order total, with nothing added, and picks an app: Cash App, Venmo, PayPal, Coinbase, Robinhood or any wallet. You can limit which tiles appear per session.
  2. We show a one-time payment address, a QR code, the exact amount to send and the network to use, with step-by-step instructions for the app they picked.
  3. The page watches the network. When the transfer confirms, the page flips to "Funds received" and we POST a signed webhook to your callback_url.
  4. Your server marks the order paid. That is it. No polling required, though you can also read the session by id.
Idempotent by design. Sessions are keyed on your transaction_id. Creating a session twice with the same id returns the same session, so retries are safe.

WooCommerce plugin

The plugin adds seven payment methods to your checkout (one per app) and handles sessions, the payment page and webhooks for you. Your store currency must be USD.

  1. Download the plugin: swtchpay-woo.zip (latest version)
  2. In WordPress admin go to Plugins, Add New, Upload Plugin, choose the zip, then Install Now and Activate.
  3. Go to WooCommerce, Settings, Swtch Pay (its own tab, next to Payments). Paste your API key and HMAC secret from the portal and save. The page reloads with your Merchant ID filled in and a green "Connected" panel.
  4. Go to WooCommerce, Settings, Payments and toggle on the Swtch Pay methods you want to offer. Click Manage on any of them to change the title or description shoppers see.
  5. Place a test order. After the shopper pays, the order moves to Processing on its own.

Refunds: open the order, click Refund and refund via Swtch Pay. We email the customer a secure link to give their receive address and send the refund once they do, out of your Swtch Pay balance, along with a per-refund fee charged only when it is sent. The order notes show each step, and your store's "Refunded order" email goes to the customer when the refund is sent. If the link expires or you cancel the refund in the portal, it is removed from the order automatically. See the refund policy.

The plugin registers a webhook receiver at https://your-site.com/wp-json/swtchpay/v1/webhook and a health check at /wp-json/swtchpay/v1/health. Make sure the WordPress REST API is not blocked by a security plugin. The plugin checks for updates about every 12 hours.

Checkout session API

Use this if you are not on WooCommerce. Authenticate with your merchant-scoped API key as a Bearer token.

Create a session

POST /api/v1/checkout-sessions
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "transaction_id": "order_10422",
  "amount_usd": 14.00,
  "callback_url": "https://example.com/swtchpay/webhook",
  "enabled_methods": ["cashapp", "venmo", "paypal", "coinbase", "robinhood", "wallet"]
}
FieldTypeNotes
transaction_idstring, requiredYour order id. Unique per merchant, used for idempotency.
amount_usdnumber, requiredThe order amount in USD. The shopper pays exactly this amount, and fees are deducted from it.
callback_urlURL, optionalPublic HTTPS endpoint that receives the signed webhook.
enabled_methodsarray, optionalAny of cashapp, venmo, paypal, coinbase, robinhood, wallet (bitcoin is coming soon). Omit to show every method enabled on your account.
metadataobject, optionalString key-value pairs stored with the session for your records (not returned in responses or webhooks).

Response

{
  "session_id": "cps_9b1e04c7a2f34d6e8c55",
  "checkout_url": "https://pay.swtchpay.com/checkout/cps_9b1e04c7a2f34d6e8c55",
  "status": "awaiting_currency",
  "amount_usd": "14.00",
  "enabled_currencies": ["USDC_SOL", "PYUSD_SOL", "USDC_BASE", "USDC_ETH"],
  "enabled_methods": ["cashapp", "venmo", "paypal", "coinbase", "robinhood", "wallet"],
  "expires_at": "2027-09-22T18:40:00.000Z",
  "payment_id": null,
  "idempotent": false
}

Redirect the shopper to checkout_url, or load it in an iframe. Sessions expire; create a new one if the shopper comes back later.

Webhooks

When a payment changes state we POST JSON to your callback_url. Every request carries an X-SwtchPay-Signature header: the hex HMAC-SHA256 of the raw request body, using your HMAC secret. Verify it before trusting the payload.

POST https://example.com/swtchpay/webhook
Content-Type: application/json
X-SwtchPay-Signature: 3b1f...e9

{
  "payment_id": "sp_5c0d2e91aa7b4f13b6e0",
  "status": "confirmed",
  "merchant_id": "sp_merch_01002",
  "transaction_id": "order_10422",
  "amount_usd": "14.00",
  "currency": "USDC_SOL",
  "crypto_amount": "14.000000000000000000",
  "wallet_address": "8xk...Qb",
  "tx_hash": "5Hj...tR",
  "received_amount": "14",
  "confirmed_at": "2026-09-22T18:12:41Z"
}
StatusMeaningWhat to do
confirmedThe full amount arrived and confirmed on the network.Mark the order paid and fulfil it.
expiredThe payment address expired before the full amount arrived.Leave the order unpaid. The shopper can start again.
failedThe payment could not complete. failure_code says why (for example an underpayment that was not topped up).Leave the order unpaid and contact the shopper if needed.

Respond with a 2xx status within 10 seconds. We retry on a 5xx, a timeout or no response: 30 seconds, 2 minutes, 10 minutes, 1 hour, 4 hours and 24 hours after the first attempt. Callbacks are idempotent on payment_id and status, so handle duplicates gracefully.

Verifying the signature

// Node
const crypto = require('crypto');
const expected = crypto.createHmac('sha256', HMAC_SECRET).update(rawBody).digest('hex');
const got = String(req.get('X-SwtchPay-Signature') || '');
const ok = got.length === 64 && crypto.timingSafeEqual(Buffer.from(got, 'hex'), Buffer.from(expected, 'hex'));

// PHP
$expected = hash_hmac('sha256', $rawBody, $hmacSecret);
$ok = hash_equals($expected, $_SERVER['HTTP_X_SWTCHPAY_SIGNATURE'] ?? '');

API keys

Keys and the HMAC secret are issued in your Swtch Pay dashboard under Integrations. Keys are merchant-scoped: a key can only create sessions for the merchant it belongs to. Keep them server-side, never in browser code. Rotate a key in the portal at any time; in-flight webhooks pick up the new secret automatically.

Questions or an integration that does not fit this page: [email protected].