API Reference · v1

Crypto Invoice API

A simple REST API to create invoices, accept crypto (USDT, BTC, ETH, LTC, BNB, Binance Pay…) and get notified when a payment lands. JSON in, JSON out. Works from any language.

Introduction

The Crypto Invoice API lets you generate invoices programmatically and accept any supported cryptocurrency. Each invoice gets a hosted pay page (mobile-first), a live status (pendingpaid), an automatic price conversion (e.g. a USDT invoice can be paid in LTC at live rate) and an optionalsuccess_redirect_url that sends the buyer back to your site 3 seconds after payment.

Quickstart

  1. Create an account on Crypto Invoice.
  2. Add a wallet under Wallets (one per currency/network).
  3. Connect your Binance API under API so payments can be verified.
  4. Create a platform API key under API → Platform keys. Save the key and secret — the secret is shown only once.
  5. Create your first invoice with the call below.
curl -X POST https://pay.itemodeverify.com/api/public/v1/invoices \
  -H "Authorization: Bearer ci_xxxxxxxxxxxx:sk_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 25,
    "currency": "USDT",
    "description": "Pro plan",
    "success_redirect_url": "https://yoursite.com/thanks"
  }'

Authentication

All API requests are authenticated with a key and a secret. Send them either as a Bearer token (recommended) or as two custom headers.

# Recommended: Bearer "<key>:<secret>"
-H "Authorization: Bearer ci_xxxxxxxxxxxx:sk_xxxxxxxxxxxx"

# Alternative: separate headers
-H "x-api-key: ci_xxxxxxxxxxxx"
-H "x-api-secret: sk_xxxxxxxxxxxx"

Never expose your secret in client-side code. Treat it like a password.

Base URL

HOSThttps://pay.itemodeverify.com

All endpoints live under /api/public/v1/. Responses are always JSON.

Invoices

The Invoice object:

{
  "id": "7b285a28-c45b-496b-831f-b84c11ca7630",
  "amount": 25,
  "currency": "USDT",
  "status": "pending",            // pending | paid | expired | cancelled
  "description": "Pro plan",
  "customer_email": null,
  "expires_at": "2026-05-21T10:00:00Z",
  "paid_at": null,
  "paid_amount": null,
  "tx_hash": null,
  "wallet_id": null,
  "tolerance_pct": 2,
  "success_redirect_url": "https://yoursite.com/thanks",
  "source": "api",
  "created_at": "2026-05-20T09:02:18Z",
  "pay_url": "https://pay.itemodeverify.com/pay/7b285a28-c45b-496b-831f-b84c11ca7630"
}

Create an invoice

POST/api/public/v1/invoices
FieldTypeDescription
amount*numberAmount due, in the invoice currency.
currency*stringUSDT, USDC, BTC, ETH, LTC, BNB, SOL, TRX or BINANCE_PAY.
descriptionstringShown to the buyer on the pay page.
customer_emailstringCustomer email (optional).
wallet_iduuidForce a specific wallet. Otherwise the buyer can pick any enabled wallet.
expires_atISO dateAbsolute expiry time.
expires_in_minutesintegerShortcut: expire N minutes from now.
tolerance_pctnumber 0-10Accepted over/under in % (default 2). Cross-currency uses min 3%.
success_redirect_urlurlBuyer is auto-redirected here 3s after payment is confirmed.
curl -X POST https://pay.itemodeverify.com/api/public/v1/invoices \
  -H "Authorization: Bearer $CI_KEY:$CI_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 49.99,
    "currency": "USDT",
    "description": "Order #1234",
    "customer_email": "buyer@example.com",
    "expires_in_minutes": 60,
    "success_redirect_url": "https://shop.example.com/order/1234/done"
  }'

Returns 201 Created with the full Invoice object.

Retrieve an invoice

GET/api/public/v1/invoices/{id}
curl https://pay.itemodeverify.com/api/public/v1/invoices/7b285a28-c45b-496b-831f-b84c11ca7630 \
  -H "Authorization: Bearer $CI_KEY:$CI_SECRET"

List invoices

GET/api/public/v1/invoices?status=pending&limit=50
FieldTypeDescription
statusstringFilter: pending | paid | expired | cancelled
limitintegerMax 200 (default 50)
curl "https://pay.itemodeverify.com/api/public/v1/invoices?status=paid&limit=20" \
  -H "Authorization: Bearer $CI_KEY:$CI_SECRET"

Response shape: { "data": Invoice[] }

Cancel an invoice

POST/api/public/v1/invoices/{id}/cancel
curl -X POST https://pay.itemodeverify.com/api/public/v1/invoices/$INVOICE_ID/cancel \
  -H "Authorization: Bearer $CI_KEY:$CI_SECRET"

Returns 409 if the invoice is already paid, expired, or cancelled.

Hosted pay page

Every invoice exposes a buyer-facing pay page at:

URLhttps://pay.itemodeverify.com/pay/{invoice_id}

It auto-detects the merchant branding (logo, colors), shows all enabled payment methods with QR + address, checks for the payment every 5 seconds, and — if you set success_redirect_url — sends the buyer back to your site 3 seconds after the payment is confirmed.

Success redirect (after-payment)

Pass a success_redirect_url when you create the invoice and the buyer will be automatically forwarded to that URL exactly 3 seconds after the payment is confirmed on the hosted pay page. The 3-second delay lets the buyer see the green "Payment received" confirmation before leaving.

The redirect URL must be absolute (https://…). We append two query parameters so your landing page can identify the order: ?invoice_id=<id>&status=paid.

1. Create the invoice with a redirect URL

curl -X POST https://pay.itemodeverify.com/api/public/v1/invoices \
  -H "Authorization: Bearer $CI_KEY:$CI_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 19.99,
    "currency": "USDT",
    "description": "Order #A-1029",
    "success_redirect_url": "https://shop.example.com/thank-you?order=A-1029"
  }'

2. Handle the redirect on your thank-you page

When the buyer lands on your URL, read the query string to identify the order. For security, never trust the URL alone — confirm the invoice status server-side (either by hitting GET /api/public/v1/invoices/{id} or by waiting for the webhook described below) before granting access to paid content.

// pages/thank-you.js (Next.js / Remix / vanilla — same idea)
const url = new URL(window.location.href);
const invoiceId = url.searchParams.get("invoice_id");
const status    = url.searchParams.get("status"); // "paid"

// Verify server-side before unlocking the order
const res = await fetch(`/api/verify-order?invoice_id=${invoiceId}`);
const { paid } = await res.json();

document.querySelector("#status").textContent =
  paid ? "Thanks! Your order is confirmed." : "Still confirming your payment…";

Tips

  • The 3-second delay is fixed. The buyer always sees the "Payment received" screen first.
  • If the buyer closes the tab before the redirect, the invoice stays paid — fulfil the order from the webhook, not the redirect.
  • If you omit success_redirect_url, the pay page simply shows the success screen and stays put.
  • The URL must be HTTPS in production. Local URLs (http://localhost) work for testing.
  • You can change the URL per-invoice — perfect for routing buyers to the right order page.

Webhooks

Add a webhook URL under API → Webhook. We POST a JSON body and an X-Signatureheader (HMAC-SHA256 of the body using your webhook secret). Verify the signature before trusting the payload.

// Webhook payload
{
  "event": "invoice.paid",
  "invoice_id": "7b285a28-c45b-496b-831f-b84c11ca7630",
  "amount": "0.00186",
  "tx": "373310330720"
}

// Header
X-Signature: 5f8c…   // hex HMAC-SHA256(body, webhook_secret)
import crypto from "node:crypto";
app.post("/webhooks/crypto-invoice", express.raw({ type: "*/*" }), (req, res) => {
  const sig = req.headers["x-signature"];
  const expected = crypto.createHmac("sha256", process.env.CI_WEBHOOK_SECRET)
    .update(req.body).digest("hex");
  if (sig !== expected) return res.status(401).end();
  const event = JSON.parse(req.body.toString());
  // mark order as paid…
  res.status(200).end();
});

IPN delivery & timing

Payments are detected by our verifier, which polls Binance for new deposits every 60 seconds. As soon as a matching transaction is found, the invoice flips to paid and we immediately POST invoice.paid to your webhook URL and fire your Telegram notification. End-to-end latency is typically 30–90 seconds from network confirmation.

FieldTypeDescription
invoice.paideventInvoice fully matched on-chain (or via Binance Pay). Sent once.
invoice.createdeventA new invoice was created via API or dashboard.
invoice.cancelledeventInvoice cancelled by you or the buyer.
invoice.expiredeventInvoice passed its expires_at without payment.
pingeventTest delivery sent from API → Webhook → Send test.

Test it: in API → Webhook, click Send test to receive a ping. To replay a real event, open any paid invoice and click Resend webhook. All attempts (status code + response body) are stored in Webhook logs.

Retries: we currently deliver each event once. If your endpoint returns a non-2xx, the failure is logged and a webhook.failed Telegram alert is sent — use the logs to resend manually. Your endpoint should respond with 200 within ~10 seconds and process asynchronously.

Errors

Errors return a standard JSON envelope:

{ "error": { "code": "invalid_input", "message": "amount: must be positive" } }
FieldTypeDescription
400invalid_json / invalid_input / invalid_walletThe request body or query was rejected.
401missing_credentials / invalid_key / invalid_secretAuthentication failed.
404not_foundThe resource doesn't exist.
409not_cancellableAction not allowed for the resource's current state.
500db_errorSomething went wrong on our end.

Full example: charge a customer end-to-end

A complete Node.js flow: create an invoice, send the buyer to the pay page, and listen for the webhook to fulfil the order.

import express from "express";
import crypto from "node:crypto";

const app = express();
const CI_KEY = process.env.CI_KEY;
const CI_SECRET = process.env.CI_SECRET;
const CI_WEBHOOK_SECRET = process.env.CI_WEBHOOK_SECRET;

// 1. Create an invoice when the user clicks "Pay"
app.post("/checkout", express.json(), async (req, res) => {
  const { orderId, amountUsd, email } = req.body;

  const r = await fetch("https://pay.itemodeverify.com/api/public/v1/invoices", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${CI_KEY}:${CI_SECRET}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: amountUsd,
      currency: "USDT",
      description: `Order #${orderId}`,
      customer_email: email,
      expires_in_minutes: 30,
      success_redirect_url: `https://shop.example.com/orders/${orderId}/thanks`,
    }),
  });
  const invoice = await r.json();

  // Save invoice.id against your order, then redirect the user
  await db.orders.update(orderId, { invoiceId: invoice.id });
  res.redirect(invoice.pay_url); // https://pay.itemodeverify.com/pay/<id>
});

// 2. Receive the webhook when the payment lands
app.post("/webhooks/crypto-invoice",
  express.raw({ type: "*/*" }),
  async (req, res) => {
    const sig = req.headers["x-signature"];
    const expected = crypto
      .createHmac("sha256", CI_WEBHOOK_SECRET)
      .update(req.body).digest("hex");
    if (sig !== expected) return res.status(401).end();

    const event = JSON.parse(req.body.toString());
    if (event.event === "invoice.paid") {
      const order = await db.orders.findOne({ invoiceId: event.invoice_id });
      await db.orders.update(order.id, { status: "paid", txHash: event.tx });
      // → fulfil the order, send a receipt, etc.
    }
    res.status(200).end();
  }
);

app.listen(3000);
Need help? Reach out via the dashboard. Base URL: https://pay.itemodeverify.com