BlitzDocs
API v1 · Stable

BlitzPayments API

Accept cryptocurrency payments in minutes. Generate a unique receiving address per invoice, let your customer pay on a beautiful hosted page, and get notified the instant funds confirm on-chain via signed webhooks.

REST & JSON

Predictable resource URLs, JSON request/response bodies, standard HTTP codes.

Multi-chain

BTC, LTC, ETH, BNB, TRX, SOL and stablecoins across TRC20 / ERC20 / BEP20 / SOL.

Signed Webhooks

HMAC-SHA256 signatures so you can trust every event you receive.

Base URL

All API requests are made to the BlitzPayments API server. Every endpoint below is relative to this base.

Production
https://api.blitzpaygate.com

During local development the API server runs on http://localhost:5000.

Quickstart

  1. 1
    Get your API key. Sign in to the Merchant Dashboard and copy your key (or rotate a new one).
  2. 2
    Create an invoice. Call POST /api/v1/invoices with the coin, network and amount.
  3. 3
    Redirect to checkout. Send the customer to the hosted payment page using the returned invoice_id.
  4. 4
    Handle the webhook. Receive an invoice.paid event and fulfil the order.
curl -X POST https://api.blitzpaygate.com/api/v1/invoices \
  -H "Authorization: Bearer bp_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "ORDER-5521",
    "coin": "USDT",
    "network": "TRC20",
    "coin_amount": 49.99
  }'
const res = await fetch("https://api.blitzpaygate.com/api/v1/invoices", {
  method: "POST",
  headers: {
    "Authorization": "Bearer bp_live_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    order_id: "ORDER-5521",
    coin: "USDT",
    network: "TRC20",
    coin_amount: 49.99,
  }),
});
const { data } = await res.json();
console.log(data.receiving_address);
<?php
$ch = curl_init("https://api.blitzpaygate.com/api/v1/invoices");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer bp_live_xxxxxxxxxxxxxxxx",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "order_id"    => "ORDER-5521",
        "coin"        => "USDT",
        "network"     => "TRC20",
        "coin_amount" => 49.99,
    ]),
]);
$response = json_decode(curl_exec($ch), true);
echo $response["data"]["receiving_address"];
import requests

res = requests.post(
    "https://api.blitzpaygate.com/api/v1/invoices",
    headers={"Authorization": "Bearer bp_live_xxxxxxxxxxxxxxxx"},
    json={
        "order_id": "ORDER-5521",
        "coin": "USDT",
        "network": "TRC20",
        "coin_amount": 49.99,
    },
)
print(res.json()["data"]["receiving_address"])

Authentication

BlitzPayments authenticates requests with a secret API key sent as a Bearer token in the Authorization header. Keys look like bp_live_… and are managed from your Merchant Dashboard.

HTTP header
Authorization: Bearer bp_live_xxxxxxxxxxxxxxxx
Keep your key secret. Treat it like a password — only use it from your server, never in browser or mobile code. If a key leaks, rotate it instantly from the dashboard; the old key stops working immediately.

Requests with a missing or invalid key return 401 Unauthorized. Suspended merchant accounts are also rejected.

Conventions & Errors

Every response is JSON and includes a top-level status field that is either "success" or "error".

Success envelope
{
  "status": "success",
  "data": { }
}
Error envelope
{
  "status": "error",
  "message": "Invalid API Key"
}

HTTP status codes

CodeMeaning
200OK — request succeeded.
201Created — a new resource (invoice) was created.
400Bad Request — missing or invalid parameters.
401Unauthorized — missing or invalid API key.
404Not Found — the resource does not exist or isn't yours.
500Server Error — something went wrong on our side.

Supported Assets

Use the exact coin and network values below when creating an invoice.

Assetcoinnetwork
BitcoinBTCBTC
LitecoinLTCLTC
EthereumETHERC20
BNB Smart ChainBNBBEP20
TronTRXTRC20
SolanaSOLSOL
Tether USDUSDTTRC20 · ERC20 · BEP20 · SOL
USD CoinUSDCTRC20 · ERC20

You supply coin_amount yourself using your own exchange rate at invoice time — the API does not fetch prices. The customer must send exactly this amount for the invoice to settle.

Create an Invoice

POST /api/v1/invoices

Creates a payment request and generates a fresh, single-use receiving address on the chosen network.

Body parameters

FieldTypeRequiredDescription
coinstringrequiredAsset symbol, e.g. USDT.
networkstringrequiredNetwork, e.g. TRC20.
coin_amountnumberrequiredExact crypto amount the customer must send.
amount_usdnumberoptionalOrder value in USD. Automatically calculated from live prices if omitted.
order_idstringoptionalYour internal order reference. Echoed back in webhooks.
user_uidstringoptionalYour end-user's identifier.
activate_modalbooleanoptionalWhen true, the response adds a checkout object for the embedded modal. See below.

Response · 201 Created

200 · application/json
{
  "status": "success",
  "data": {
    "invoice_id": "48273910",
    "order_id": "ORDER-5521",
    "coin": "USDT",
    "network": "TRC20",
    "amount_usd": 49.99,
    "coin_amount": 49.99,
    "receiving_address": "TJ8x...wxyz",
    "expires_at": "2026-06-05T13:00:00.000Z"
  }
}

The returned invoice_id is an 8-digit reference (a string, e.g. "48273910") — use it for the hosted checkout URL and to fetch the invoice. Invoices expire 1 hour after creation; persist the id against your order so you can reconcile the webhook later.

Get an Invoice

GET /api/v1/invoices/{id}

Retrieves the current state of one of your invoices. Poll this to check status, or rely on webhooks (recommended).

Path parameters

FieldTypeDescription
idstringThe 8-digit invoice_id returned when the invoice was created.
curl https://api.blitzpaygate.com/api/v1/invoices/48273910 \
  -H "Authorization: Bearer bp_live_xxxxxxxxxxxxxxxx"
const res = await fetch("https://api.blitzpaygate.com/api/v1/invoices/48273910", {
  headers: { "Authorization": "Bearer bp_live_xxxxxxxxxxxxxxxx" },
});
const { data } = await res.json();
console.log(data.status); // "pending" | "paid" | "underpaid" | "expired"

Response · 200 OK

200 · application/json
{
  "status": "success",
  "data": {
    "id": 124,
    "public_id": "48273910",
    "merchant_uid": "MERCH_3f9a...",
    "user_uid": "user_987654321",
    "order_id": "ORDER-5521",
    "coin": "USDT",
    "network": "TRC20",
    "amount_usd": "49.99000000",
    "coin_amount": "49.99000000",
    "receiving_address": "TJ8x...wxyz",
    "status": "paid",
    "expires_at": "2026-06-05T13:00:00.000Z",
    "created_at": "2026-06-05T12:00:00.000Z"
  }
}

Test Webhook

POST /api/v1/webhooks/test

Triggers a test delivery so you can confirm your endpoint and signature verification are wired up correctly.

Request
curl -X POST https://api.blitzpaygate.com/api/v1/webhooks/test \
  -H "Authorization: Bearer bp_live_xxxxxxxxxxxxxxxx"

Health Check

GET /api/health

A public, unauthenticated endpoint for uptime monitoring.

200 · application/json
{ "status": "success", "message": "BlitzPayments API is running" }

Hosted Checkout

The fastest way to collect payment is the BlitzPayments hosted page. After creating an invoice, redirect the customer using the returned invoice_id. The page renders the exact amount, a QR code, the receiving address, and a live countdown — and updates automatically when the payment confirms.

Redirect URL
https://your-domain.com/payment.php?id={invoice_id}
The page shows three states automatically: Awaiting payment (with QR + countdown), Payment complete, and Invoice expired.

Embedded Checkout

Keep customers on your page. Our lightweight JavaScript SDK pops the checkout in a modal overlay (an iframe over the hosted page) instead of redirecting — and emits onPaid / onExpired events as the on-chain status changes live.

Create the invoice on your server. The create-invoice call needs your secret key, so always run it server-side, then hand the returned checkout object (or just the invoice_id) to the browser. The SDK never sees your API key.

Step 1 — Create with activate_modal (server-side)

The response now carries a checkout object alongside the usual fields:

201 · application/json
{
  "status": "success",
  "data": {
    "invoice_id": "48273910",
    "receiving_address": "TJ8x...wxyz",
    "hosted_url": "https://your-domain.com/payment.php?id=48273910",
    "activate_modal": true,
    "checkout": {
      "invoiceId": "48273910",
      "embed_url": "https://your-domain.com/payment.php?id=48273910&embed=1",
      "script_url": "https://your-domain.com/checkout.js"
    }
  }
}

Step 2 — Open the modal (browser)

Pick whichever fits your stack. Option A writes no JavaScript at all.

Option A — Zero JavaScript (recommended)

Drop in the script once and add a data-blitz-checkout attribute to any button/link. The SDK auto-wires the click, opens the modal, tracks status live, and (optionally) redirects when paid:

your-page.html
<script src="https://your-domain.com/checkout.js"></script>

<!-- invoice_id (48273910) comes from your server's create-invoice call -->
<button data-blitz-checkout="48273910"
        data-blitz-success-url="/thank-you">Pay with crypto</button>

Trigger data-* attributes

AttributeDescription
data-blitz-checkoutRequired. The 8-digit invoice id to open.
data-blitz-success-urlRedirect here once payment confirms (invoice_id is appended as a query param).
data-blitz-embed-urlExplicit embed_url from the API response. Overrides the id.
data-blitz-base-urlOverride the storefront origin (defaults to where checkout.js is served from).

Need a hook without writing an open() call? The trigger element also fires bubbling DOM events blitz:paid, blitz:expired and blitz:close. Injecting buttons dynamically? Call BlitzCheckout.bind() to wire up new ones.

Option B — Programmatic

For full control, pass the checkout object (or an invoiceId) to BlitzCheckout.open():

your-page.html
<script src="https://your-domain.com/checkout.js"></script>
<button id="pay">Pay with crypto</button>

<script>
  document.getElementById('pay').onclick = () => {
    BlitzCheckout.open({
      invoiceId: '48273910',           // from your server's create-invoice call
      onPaid:    (inv) => { window.location = '/thank-you?o=' + inv.order_id; },
      onExpired: ()    => { alert('Invoice expired, please retry.'); },
      onClose:   (e)   => { /* e.settled tells you if it was paid */ },
    });
  };
</script>

BlitzCheckout.open(options)

OptionTypeDescription
invoiceIdstringThe 8-digit invoice id. Required (unless embed_url is given).
embed_urlstringFull embed URL from the API. Overrides invoiceId.
onPaidfunctionCalled with the invoice when payment confirms.
onExpiredfunctionCalled when the invoice expires.
onClosefunctionCalled when the modal closes. Receives { reason, settled }.

The modal can be dismissed with the close button, the backdrop, or Esc, and auto-closes shortly after a paid/expired result. Call BlitzCheckout.close() to dismiss it programmatically.

Invoice Lifecycle

Our blockchain monitor watches each receiving address and advances the invoice's status automatically.

pending

Invoice created, awaiting payment. The default state.

underpaid

Funds arrived but were less than coin_amount. The customer must top up the difference to the same address.

paid

Full amount confirmed on-chain. Your balance is credited and an invoice.paid webhook fires.

expired

No full payment within the 1-hour window. Create a new invoice to retry.

Webhooks

When an invoice is paid, BlitzPayments sends an HTTP POST to the Webhook URL configured in your dashboard. Respond with 2xx quickly; do heavy work asynchronously.

Event payload

POST to your webhook URL
{
  "event": "invoice.paid",
  "data": {
    "invoice_id": "48273910",
    "order_id": "ORDER-5521",
    "status": "paid",
    "amount_usd": "49.99000000",
    "coin": "USDT",
    "network": "TRC20",
    "tx_hash": "0xabc123..."
  },
  "timestamp": 1717593600000
}

Verifying signatures

Every request carries an X-BlitzPayments-Signature header: a hex HMAC-SHA256 of the raw request body keyed with your API key. Recompute it and compare using a constant-time check before trusting the event.

const crypto = require("crypto");

// IMPORTANT: use the raw body string, exactly as received.
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const raw = req.body.toString("utf8");
  const expected = crypto
    .createHmac("sha256", process.env.BLITZ_API_KEY)
    .update(raw)
    .digest("hex");

  const received = req.get("X-BlitzPayments-Signature") || "";
  const ok = expected.length === received.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));

  if (!ok) return res.status(401).send("bad signature");

  const event = JSON.parse(raw);
  if (event.event === "invoice.paid") {
    // fulfil the order for event.data.order_id
  }
  res.sendStatus(200);
});
<?php
$raw = file_get_contents("php://input");
$expected = hash_hmac("sha256", $raw, getenv("BLITZ_API_KEY"));
$received = $_SERVER["HTTP_X_BLITZPAYMENTS_SIGNATURE"] ?? "";

if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit("bad signature");
}

$event = json_decode($raw, true);
if ($event["event"] === "invoice.paid") {
    // fulfil the order for $event["data"]["order_id"]
}
http_response_code(200);
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)

@app.post("/webhook")
def webhook():
    raw = request.get_data()  # raw bytes, do not re-serialize
    expected = hmac.new(os.environ["BLITZ_API_KEY"].encode(),
                        raw, hashlib.sha256).hexdigest()
    received = request.headers.get("X-BlitzPayments-Signature", "")

    if not hmac.compare_digest(expected, received):
        abort(401)

    event = request.get_json()
    if event["event"] == "invoice.paid":
        ...  # fulfil the order
    return "", 200

Best practices.

  • Always verify the signature against the raw body before parsing JSON.
  • Make handling idempotent — key on invoice_id so re-deliveries don't double-fulfil.
  • Return 2xx fast; queue downstream work.
  • Treat the webhook as the source of truth, but you can confirm with GET /invoices/{id}.

Withdrawals & Charges

Paid invoices credit your per-asset balance. You withdraw funds from the Merchant Dashboard (Withdrawals → Request Withdrawal): pick the asset, enter an amount, and provide your destination address for that coin.

1 · Request

Your balance is locked for the requested amount.

2 · Charge

A percentage fee is deducted; the rest is your net payout.

3 · Settle

An admin processes it: the charge goes to the platform wallet, the net to your address.

Each asset has a minimum withdrawal — requests below it are blocked, and the minimum plus the exact fee are shown live in the request form before you confirm. Your payout address for each coin is remembered for next time. If a request is rejected, the locked balance is refunded in full. A programmatic withdrawals API is on the roadmap.

Error Reference

Common errors and how to resolve them.

HTTPMessageFix
400Missing required parameters: coin, network, amount_usd, coin_amountInclude all four required fields in the JSON body.
401Missing or invalid Authorization headerSend Authorization: Bearer <key>.
401Invalid API KeyCheck the key; ensure your account is active.
404Invoice not foundThe id is wrong or belongs to another merchant.
500Failed to create invoiceRetry; if it persists, the coin/network may be unsupported.