Developers
Create an invoice with one REST API request, and your server hears about every payment and payout through a signed webhook.
Three steps to connect
- Open the shop in the dashboard and issue an API key under “API”. “Invoices only” access is enough for invoices; payouts need full access. The key is shown once, so keep it on your server.
- Set the webhook URL under “Webhook” and save the signing secret.
- Create an invoice and send the buyer to the pay_url from the response.
An invoice in one request
curl -X POST https://<domain>/api/v1/invoices \
-H "Authorization: Bearer cpk_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042" \
-d '{"currency": "USD", "amount": "49.90", "reference": "order-1042"}'A retry with the same Idempotency-Key never creates a second invoice. Amounts are strings, and times are UTC.
Events
- payment.seen, payment.detected, payment.confirmed, payment.orphaned: seen, found in a block, credited, rolled back
- invoice.paid, invoice.partially_paid, invoice.expired, invoice.cancelled: invoice state
- payout.broadcast, payout.confirmed, payout.failed: payout sent, confirmed, failed
An event counts as delivered when your server answers 2xx within 10 seconds. Otherwise CoinsPay retries it with growing pauses: 20 attempts over about a day.
Verifying the signature
import crypto from 'node:crypto';
// rawBody is the request body exactly as received, before JSON.parse.
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) <= 300;
return fresh && crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}Go, PHP and Python samples are in the dashboard under “Webhook” and in the API reference.
Limits
- Up to 600 requests a minute per IP.
- Up to 60 requests a minute per shop, counted separately for addresses, invoices and payouts.
- Every method and field is described in the API reference.
Start taking crypto today
Signing up takes a minute and setting up a shop about five more. Connecting is free.