From API keys to your first settled payment. Most merchants integrate AssetPay in under a day — one endpoint to create payments, one redirect, one webhook.
Apply for a merchant account. Once KYB review is complete (typically 3 business days), you'll receive two keys:
| Key | Where it lives |
|---|---|
sk_live_… | Your server. Used to create payments and access account data. Treat it like a password. |
pk_live_… | The browser. Used by the hosted checkout — you rarely touch it directly. |
POST /merchant/keys/rotate-secret.When a customer checks out, call POST /payments with the USD amount. Use an Idempotency-Key so network retries never create duplicates.
const res = await fetch('https://api.assetpay.io/payments', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ASSETPAY_SECRET_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': `order-${order.id}`, }, body: JSON.stringify({ amountUsd: '149.99', orderId: order.id, successUrl: 'https://yourstore.com/thanks', cancelUrl: 'https://yourstore.com/cart', }), const payment = await res.json(); // => { id, status: 'CREATED', checkoutUrl, expiresAt, ... }
Send the customer to payment.checkoutUrl. The hosted page handles everything — crypto network selection (TRON USDT, Base USDC, Polygon USDC), card entry with 3-D Secure, live confirmation tracking, and the final redirect back to your successUrl.
// Express example res.redirect(303, payment.checkoutUrl);
No iframe, no card data on your servers — keeps you out of PCI scope.
Set your webhook URL in the dashboard (or via PATCH /merchant/settings). Fulfil orders on payment.treasury_received — that's when funds are final. Always verify the signature first.
app.post('/webhooks/assetpay', express.raw({ type: '*/*' }), (req, res) => { const ok = verifyWebhook( process.env.ASSETPAY_WEBHOOK_SECRET, req.body.toString(), req.headers['x-assetpay-signature'], ); if (!ok) return res.status(401).end(); const event = JSON.parse(req.body); switch (event.type) { case 'payment.treasury_received': fulfillOrder(event.data.orderId); // funds are final break; case 'payment.expired': case 'payment.failed': releaseInventory(event.data.orderId); break; } res.json({ received: true }); });
The verifyWebhook implementation is in the API docs — HMAC-SHA256 over timestamp.body with a 5-minute replay window.
Run an end-to-end test before launch:
| Check | What to verify |
|---|---|
| Create & pay | Payment reaches TREASURY_RECEIVED; customer lands on your successUrl. |
| Webhooks | Your endpoint receives events, verifies signatures, and responds 2xx within 10s. |
| Expiry | An unpaid payment transitions to EXPIRED and your inventory is released. |
| Refunds | POST /payments/:id/refund creates a PENDING refund visible in your dashboard. |
| Idempotency | Replaying the same Idempotency-Key returns the original payment, not a duplicate. |
Settlement runs T+7 for your first four weeks, then automatically upgrades to T+3. Stablecoins settlement (USDC/USDT) is available for qualifying merchants — see settlement terms.