Quickstart
Zero to a verified API call in under ten minutes.
1. Get an API key
Section titled “1. Get an API key”Sign in to the merchant dashboard with email-OTP, attach a wallet, and create an API key under Settings → API keys. The raw key is shown once — store it in your secret manager. Server keys are prefixed sk_live_*.
To test without touching mainnet, create sessions with sandboxMode: true (see step 5) — same key, same host, payment options restricted to testnet chains.
2. Make your first request
Section titled “2. Make your first request”Create a payment session:
curl -X POST https://api.harness.stablecoinx.com/v1/sessions \ -H "Authorization: Bearer $STABLECOINX_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": "10.00", "merchantName": "Acme Inc.", "paymentOptionSymbols": ["USDC", "USDT", "USDe"], "expiresInSec": 1800, "successUrl": "https://example.com/thanks" }'Response:
{ "id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "paymentUrl": "https://pay.stablecoinx.com/session/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "status": "awaiting_payment", "expiresAt": "2026-05-26T17:30:00Z", "createdAt": "2026-05-26T17:00:00Z"}paymentUrl is what you send the customer. Per-chain deposit addresses live inside the session’s paymentOptions[] (fetch them via GET /v1/sessions/:id).
3. Track the payment
Section titled “3. Track the payment”Redirect the customer to paymentUrl. They pick a stablecoin + chain and transfer the exact amount to the displayed deposit address. Then either receive a webhook (recommended) or poll status (no auth required for this endpoint):
curl https://api.harness.stablecoinx.com/v1/sessions/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/status# → { "status": "confirming", "webhookDelivered": true }The session moves through pending → awaiting_payment → confirming → bridging → completed (terminal: completed | failed | expired). When status is completed, funds have settled to your merchant wallet as sUSDe.
4. Verify webhook signatures
Section titled “4. Verify webhook signatures”Each delivery carries X-StablecoinX-Signature: t=<unix>,v1=<hmac> and X-StablecoinX-Event-Id. The signature is HMAC-SHA256 of "{timestamp}.{rawBody}" using your endpoint secret. Verify on receipt, compare in constant time, and reject signatures older than ~5 minutes:
import crypto from "node:crypto";
// Capture the *raw* body — JSON-parsing first will reshuffle bytes and break the HMAC.const sigHeader = req.header("X-StablecoinX-Signature") ?? "";const m = /^t=(\d+),v1=([0-9a-f]+)$/.exec(sigHeader);if (!m) return res.status(400).end();const [, tsStr, theirSig] = m;const ts = Number(tsStr);
if (Math.abs(Date.now() / 1000 - ts) > 300) return res.status(400).end();
const expected = crypto .createHmac("sha256", process.env.STABLECOINX_WEBHOOK_SECRET!) .update(`${ts}.${req.rawBody.toString("utf8")}`) .digest("hex");
const ok = crypto.timingSafeEqual( Buffer.from(theirSig, "hex"), Buffer.from(expected, "hex"),);if (!ok) return res.status(401).end();Today the API emits a single event type, session.confirming. More event types are coming.
5. Test mode and going live
Section titled “5. Test mode and going live”There is one production host and one API shape; test mode is per-session, not a separate environment:
- Test: pass
sandboxMode: trueonPOST /v1/sessions. Payment options are restricted to testnet chains (Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia); pay with testnet stablecoins. The rest of the pipeline (forwarder, swap, webhook) is the same code path mainnet runs. - Live: pass
sandboxMode: false(or omit it). Supported mainnets:base,arbitrum,ethereum.
sandboxMode is strictly validated — send a real boolean; a non-boolean value returns 400.
Where to next
Section titled “Where to next”- Session Payment — the payment flow in depth.
- Paymaster API — sponsor gas or let users pay in stablecoins.
- Treasury Dashboard — operate the funds you’ve settled.