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
awaiting | No transfer seen yet. Expires 60 minutes after creation. |
detected | A transfer is in the mempool or a recent block; confirmations are counting. |
confirmed | Threshold reached (BSC 3, Ethereum 2, Tron 19, Bitcoin 1 by default). |
paid | Fee computed, ledger written, invoice.paid webhook queued, sweep scheduled. |
swept | Net amount forwarded to your settlement wallet; sweep_tx_hash is set. |
expired | Nothing 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.