Build it with an AI agent
Give this to your AI agent
Paste it into Claude Code, Cursor or any agent that can read a URL. It reads the OpenAPI contract and the signing recipe, and follows the rules for handling real funds.
Read https://www.payaries.com/ai-agents.md and integrate Payaries crypto payments into this project. Follow its rules for handling real funds.Never paste your API secret into an agent. Keep it in an environment variable.
01What the API does
Payaries is a multi-chain crypto payment gateway. Your backend talks to it over HTTPS; your customers never see it. The surface a payment integration needs is small:
POST /v1/invoices— creates an invoice for a fiat amount in a chain and asset you choose, locks the exchange rate, and returns a one-time deposit address.GET /v1/invoices/:id— the invoice's current status, confirmations and, once forwarding starts, its payout.- Webhooks — a signed
invoice.status_changedevent on every transition, andwithdrawal.status_changedfor payouts. POST /v1/withdrawals— sends funds from your own wallet to any address you name.GET /v1/chainsandGET /v1/rates/:asset/:fiat— public endpoints for the live chain and asset list and informational prices.
The whole contract is published as an OpenAPI document at /openapi.json, with a stable operationId on every operation. Building with an AI coding assistant? Start at Payaries for AI agents.
02Authentication: signed requests
Server-to-server calls carry an API key and an HMAC-SHA256 signature over the timestamp, HTTP method, request target (path plus query string) and body. The secret never leaves your server.
const crypto = require('crypto');
const timestamp = Date.now().toString();
const body = JSON.stringify(requestBody ?? {});
const message = `${timestamp}\n${method.toUpperCase()}\n${requestTarget}\n${body}`;
const signature = crypto.createHmac('sha256', apiSecret).update(message).digest('hex');- Requests older than five minutes are rejected, so keep your server clock in sync.
- Each signature is single-use for state-changing requests (
POST,PATCH,DELETE). A retry needs a fresh timestamp and a new signature. - API keys can be restricted to a list of IP addresses.
- Managing API keys, rotating the webhook secret, changing the webhook URL or redirect domains and approving withdrawals are dashboard-session-only actions — a leaked API key can't do any of them.
03Create an invoice
referenceId is your idempotency key: replaying the same value for your account returns the existing invoice instead of creating a duplicate, so a network retry can never double-bill.
POST /v1/invoices
X-Api-Key: <your api key>
X-Timestamp: 1725700000000
X-Signature: <hex HMAC-SHA256>
{
"referenceId": "order_10231",
"fiat": { "amount": "49.99", "currency": "USD" },
"crypto": { "asset": "USDT_TRC20", "chainId": "tron-mainnet" },
"metadata": { "customerId": "cus_123" }
}201 Created
{
"referenceId": "order_10231",
"crypto": { "asset": "USDT_TRC20", "chainId": "tron-mainnet", "amountDue": "49.99", "rateLocked": "1" },
"depositAddress": { "value": "TXyz..." },
"status": "pending",
"confirmations": { "required": 19, "current": 0 },
"expiresAt": "2026-09-08T00:30:00.000Z"
}Show depositAddress.value to your customer (as text and a QR code). The fiat amount is converted at creation and the rate stays locked for that invoice.
04The invoice lifecycle
An invoice moves through pending → detected → confirming → confirmed, then forwarding → settled as the deposit is swept to your wallet. Your ledger is credited the moment it reaches confirmed; that credit becomes withdrawable once the sweep settles.
expired, underpaid and failed are the off-ramps. expired is final unless you later get a transition out of it: a payment made on time but noticed late moves it to detected or underpaid, while one mined after the deadline is held for review (see below). See handling underpaid and late payments.
05Webhooks
Every status change is delivered as a signed POST. Verify the X-Gateway-Signature header — an HMAC-SHA256 of the timestamp and the raw body — before you trust it. Failed deliveries are retried immediately, then after 1 minute, 5 minutes, 15 minutes, 1 hour and 6 hours.
function verifyWebhook(rawBody, signature, timestamp, webhookSecret, toleranceMs = 5 * 60 * 1000) {
if (Math.abs(Date.now() - timestamp) > toleranceMs) return false;
const expected = crypto
.createHmac('sha256', webhookSecret)
.update(timestamp + rawBody)
.digest('hex');
const a = Buffer.from(expected, 'hex');
const b = Buffer.from(signature, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}The full walkthrough, including dedupe and ordering, is in verifying crypto webhook signatures.
06Withdrawals
Withdraw to any address, not just a pre-registered one. With an API key the Idempotency-Key header is required: the same key with the same parameters returns the original withdrawal, and the same key with different parameters is a 409. Withdrawals created by an API key execute immediately below your auto-approve threshold and wait for your approval in the dashboard above it.
Withdrawals are sent from your own wallet, which needs a little of the chain's native currency (ETH, BNB, POL or TRX, for example) to pay network gas on chains where Payaries's gas station doesn't cover it — it isn't topped up for you. Where the station covers a chain, the gas is recovered as a network fee inside the transaction instead.
07Supported networks
| Network | Assets | Deposits | Withdrawals |
|---|---|---|---|
| Ethereum mainnet | ETH, USDT (ERC-20), USDC (ERC-20), DAI, WBTC and more | Yes | Yes |
| BNB Smart Chain | BNB, USDT (BEP-20), USDC (BEP-20), DAI and more | Yes | Yes |
| Polygon | POL, USDT, USDC, DAI, WBTC | Yes | Yes |
| Arbitrum | ETH, USDT, USDC, DAI, WBTC | Yes | Yes |
| Tron mainnet | TRX, USDT (TRC-20) | Yes | Yes |
| Bitcoin | BTC | Yes | Not yet |
More networks and assets are being added. The authoritative list is always the public GET /v1/chains endpoint — an asset only appears there once it is actually configured.
08Errors, limits and what to know first
- Errors are plain JSON (
{ "error": "…" }) with conventional status codes:400validation,401auth or replayed signature,403forbidden,404not found,409conflict,429rate limited,503a security dependency is temporarily unavailable — retry with a fresh signature. - Rate limits: 120 requests a minute per IP overall, and 20 a minute for creating invoices or withdrawals.
- Payaries runs on real mainnet networks only. There is no sandbox — test-mode API keys transact on the same chains as live keys, so integration testing uses a small real payment. Live keys are issued once your account is approved.
- Crypto transactions are irreversible once confirmed. A refund to a customer is a separate transaction you send yourself.
Questions
- Is there a sandbox or testnet for the crypto payment API?
- No. Payaries runs on real mainnet networks only. Test-mode API keys work immediately and transact on the same real chains as live keys; "live" only means your account has been approved. Test an integration with a small real payment.
- How do I authenticate requests to the API?
- Send your API key in X-Api-Key, the current time in X-Timestamp and an HMAC-SHA256 signature in X-Signature. The signature covers the timestamp, HTTP method, request path and query string, and body, and is computed with your API secret.
- How do I avoid creating duplicate invoices or withdrawals?
- Invoices use your referenceId as the idempotency key — the same value returns the existing invoice. Withdrawals made with an API key require an Idempotency-Key header; the same key with the same parameters returns the original withdrawal.
- What happens if my webhook endpoint is down?
- Deliveries are retried on a schedule that spans six hours: immediately, then after 1 minute, 5 minutes, 15 minutes, 1 hour and 6 hours. After the final failure an invoice's webhookStatus becomes failed, and you can re-send it with POST /v1/invoices/:id/resend-webhook.
- Which blockchains does the crypto payment API support?
- Ethereum, BNB Smart Chain, Polygon, Arbitrum and Tron support deposits and on-chain withdrawals, and more chains are on the way. Bitcoin supports deposits only for now. Call GET /v1/chains for the live list.
Keep reading
- Crypto payment API quickstart: from signup to your first payoutTake your first crypto payment through the Payaries API: create a key, submit the business profile, create an invoice, handle the webhook and withdraw. Real requests and responses.
- How to sign crypto payment API requests (HMAC-SHA256)How to sign Payaries API requests with HMAC-SHA256, with working Node.js, Python, Go and shell code and published test vectors to check your implementation against.
- Build a crypto payment integration with an AI agent, safelyEverything an AI agent or coding assistant needs to integrate Payaries: an OpenAPI spec, llms.txt, markdown docs, signing test vectors and the rules for handling real funds safely.
- How to verify crypto payment webhook signaturesVerify a crypto payment webhook's HMAC-SHA256 signature against the raw body, guard against replays, dedupe retries and acknowledge fast — with working Node.js code.
- How a crypto payment gateway works, from invoice to settlementHow a crypto payment gateway works, step by step: invoices, one-time deposit addresses, confirmations, settlement and withdrawals.
- Accept USDT payments on Ethereum, BNB Smart Chain, Polygon, Arbitrum, Tron and moreAccept USDT on Ethereum, BNB Smart Chain, Polygon, Arbitrum and Tron — and more networks as they ship — through one API, with a locked fiat rate and on-demand withdrawals.
- Custom token payments: bring your own ERC-20, BEP-20 or TRC-20 tokenRequest your own ERC-20, BEP-20 or TRC-20 token on your Payaries account. How review works, and how invoices, fees and withdrawals work once it is approved.