NZenqPay

Integrate ZenqPay

Everything below works identically on testnet and mainnet. Base URL: https://zenqpay.com.

1. API keys

Sign in to the dashboard and open API Vault. Each key has a public id and a secret that is shown once. Send both headers on every /v1/* call:

X-Api-Key: ZQP-XXXXXX-XXXXXX-XXXXXX
X-Api-Secret: sk_...

Ten failed attempts from one IP within 15 minutes lock that IP out for the rest of the window (HTTP 429 with Retry-After).

2. Create an Express invoice

Express invoices carry no amount: the customer may send any sum. Choose an asset and a network.

POST https://zenqpay.com/v1/express/invoices
{"asset": "USDT", "network": "TRC20"}

Assets: USDT, USDC, BTC. Networks: ERC20, BEP20, POLYGON, ARBITRUM, BASE, OP, TRC20, BTC. BTC only pairs with the BTC network.

{
  "invoice_id": "inv_...",
  "address": "T...",
  "asset": "USDT",
  "network": "TRC20",
  "checkout_url": "https://zenqpay.com/pay/inv_...",
  "expires_at": "2026-01-01T12:00:00+00:00",
  "status": "awaiting"
}

Read it back with GET /v1/express/invoices/{id} (adds amount, tx_hash, confirmations, platform_fee_usd, net_amount, sweep_status) and list with GET /v1/express/invoices?page=1&per_page=25.

3. Hosted checkout & status

Send the customer to checkout_url. The page shows the address, a QR code, your branding and a 60-minute countdown, and polls GET /pay/{id}/status every five seconds until the payment is confirmed.

4. Embed on your site

Load /embed.js from your gateway host and open the checkout in a locked modal. The modal cannot be dismissed until the payment is confirmed or the invoice expires; your callback receives the paid event.

<script src="https://zenqpay.com/embed.js"></script>
<button id="pay">Pay with crypto</button>
<script>
  document.getElementById("pay").onclick = function () {
    ZenqPay.open({
      checkoutUrl: "https://zenqpay.com/pay/inv_...",   // from the create call
      onPaid: function (event) { window.location.href = "/thank-you"; },
      onExpired: function () { alert("This checkout expired — please start again."); }
    });
  };
</script>

The event object contains invoice_id, status, amount and tx_hash. Messages are only accepted from your gateway's origin, and the checkout only posts back to the page that opened it. Treat the browser event as a UX hint — release goods from the webhook, never from the browser.

5. Invoice statuses

awaitingNo transfer seen yet. Expires 60 minutes after creation.
detectedA transfer is in the mempool or a recent block; confirmations are counting.
confirmedThreshold reached (BSC 3, Ethereum 2, Tron 19, Bitcoin 1 by default).
paidFee computed, ledger written, invoice.paid webhook queued, sweep scheduled.
sweptNet amount forwarded to your settlement wallet; sweep_tx_hash is set.
expiredNothing arrived in time. A late transfer within 24 hours still credits the invoice.

6. Webhooks

Set your endpoint under Event Streams. Only public HTTPS hosts are accepted. Events are invoice.paid and invoice.expired; each delivery is retried up to eight times with exponential backoff until your endpoint answers 2xx.

POST https://your-site.com/zenqpay/webhook
Content-Type: application/json
X-ZenqPay-Signature: sha256=<hex HMAC-SHA256 of the raw body>
X-ZenqPay-Timestamp: 1767268800
X-ZenqPay-Delivery: 6146147f-75c6-4450-b730-25121d977437

{"amount":"25","asset":"USDT","delivery_id":"6146147f-...","event":"invoice.paid",
 "invoice_id":"inv_...","net_amount":"24.5","network":"TRC20","paid_at":"2026-01-01T12:03:41+00:00",
 "platform_fee_usd":"0.5","tx_hash":"..."}

Credit the customer once per invoice_id. Retries reuse the same delivery_id and identical bytes, so a duplicate is safe to ignore.

7. Verify the signature

Compute HMAC-SHA256 over the exact raw request body with your webhook secret and compare in constant time.

Python

import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)

PHP

$raw    = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_ZENQPAY_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $raw, $secret);
if (!hash_equals($expected, $header)) { http_response_code(401); exit; }
$event = json_decode($raw, true);

Use the Send test event button in Event Streams to fire a webhook.test delivery at your endpoint.

8. Dashboard handoff

An external client area can mint a one-time dashboard sign-in link for the merchant using the API credentials. Pass the end user's IP to bind the link to their device.

POST https://zenqpay.com/v1/auth/handoff
{"ip": "203.0.113.9"}

{"sign_in_url": "https://zenqpay.com/auth/verify?token=...", "expires_at": "...", "single_use": true}

9. DHRU Fusion plugin

The gateway ships a DHRU Fusion payment module with an add-funds widget and a signature-verified callback that credits a client balance exactly once. Download it from /download/dhru-gateway, upload the modules/gateways files, and enter your API key and webhook secret in the gateway settings. The module registers its callback URL with ZenqPay on first save.