// docs

Developer documentation

Integrate NextCryptoPay in a few minutes. Here is the shape of a typical integration.

Building with an AI agent?

If you're using Claude Code, Codex, Cursor or any AI agent to build your project, download docs-agent.md and hand it to your agent — it contains everything needed to integrate NextCryptoPay automatically.

Download docs-agent.md

1. Create an API key

Generate a key in Dashboard → API keys. Keep the secret on your server, never in the browser.

2. Create an invoice

POST the amount, currency and chain to the invoices endpoint, then redirect the customer to the returned checkout URL.

3. Receive webhooks

We send a signed webhook when an invoice is paid, confirming, or expired. Verify the signature with your webhook secret.

Authentication

Authenticate every request with your secret key in the Authorization header. Create keys per shop in Dashboard → API keys (the full key is shown once).

Create an invoice

Send the order amount and asset; the chain is optional. You get back a hosted checkoutUrl — redirect your customer there. Without a chain, the customer picks the network on the checkout page.

Request

curl -X POST https://nextcryptopay.com/api/v1/invoices \
  -H "Authorization: Bearer ncp_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "orderId": "ORDER-1001",
    "amount": 99.50,
    "currency": "USD",
    "chain": "tron",
    "asset": "USDT",
    "webhookUrl": "https://yourstore.com/webhooks/nextcryptopay",
    "redirectUrl": "https://yourstore.com/thank-you"
  }'

Response

{
  "id": "inv_abc123",
  "orderId": "ORDER-1001",
  "payAddress": "TJ9xH4n2k8sQw7Lm3vR5pZ1aB6cD8eF2g",
  "cryptoAmount": "99.50",
  "asset": "USDT",
  "chain": "tron",
  "status": "PENDING",
  "expiresAt": "2026-06-17T10:00:00.000Z",
  "checkoutUrl": "https://nextcryptopay.com/pay/inv_abc123"
}

redirectUrl is where the customer is sent a few seconds after paying. Omit it and the shop's Return URL (Dashboard → Webhooks) is used instead. Set one of the two — with neither, the customer is left on the payment page with no way back to your store. Never fulfil an order just because someone landed on that URL: only a verified invoice.paid webhook proves payment.

Track payment status

Poll the invoice, or subscribe to live updates via Server-Sent Events. Statuses: PENDING → CONFIRMING → PAID (or EXPIRED / PARTIALLY_PAID).

# Poll the invoice
curl https://nextcryptopay.com/api/v1/invoices/inv_abc123

# Or subscribe to live updates (Server-Sent Events)
GET https://nextcryptopay.com/api/v1/invoices/inv_abc123/stream

Verify webhooks

On each status change we POST a signed event to your webhook URL. Verify the x-nextcryptopay-signature header (HMAC-SHA256 of the raw body using your shop's webhook secret) before trusting it. Return 2xx within 15s — we retry with backoff otherwise. The legacy x-cryptopay-* headers are still sent in parallel with identical values until 2027-03-31; prefer the x-nextcryptopay-* names in new code.

import crypto from "node:crypto";

// Legacy x-cryptopay-* headers carry identical values and are still sent in
// parallel until 2027-03-31 — prefer x-nextcryptopay-* in new code.
app.post("/webhooks/nextcryptopay", (req, res) => {
  const signature = req.headers["x-nextcryptopay-signature"];
  const timestamp = req.headers["x-nextcryptopay-timestamp"];

  // Reject stale deliveries (replay protection): within 5 minutes
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
    return res.status(401).end();
  }

  // Signature is HMAC of "timestamp.rawBody"
  const expected = crypto
    .createHmac("sha256", process.env.NEXTCRYPTOPAY_WEBHOOK_SECRET)
    .update(timestamp + "." + req.rawBody) // raw JSON body
    .digest("hex");

  if (
    signature.length !== expected.length ||
    !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
  ) {
    return res.status(401).end();
  }

  // Dedupe by delivery id (same event may be retried)
  const deliveryId = req.headers["x-nextcryptopay-delivery"];
  if (alreadyProcessed(deliveryId)) return res.status(200).end();

  const { event, invoice } = req.body;
  if (event === "invoice.paid") fulfillOrder(invoice.orderId);

  res.status(200).end(); // reply 2xx within 15s, else we retry (6 attempts, backoff)
});

Supported chains

Tron (USDT/USDC · TRC20), Ethereum (USDT/USDC · ERC20), BSC (USDT · BEP20), TON (USDT · jetton), Bitcoin (BTC). A platform fee applies to each successful payment and is capped per transaction, charged from your prepaid USDT balance (or covered by your plan allowance). See the Pricing page for current rates.