Clearqo API
Accept USDT through Binance Pay, TRC20 and BEP20 from any website, app or bot. Customers pay directly into your own Binance account — Clearqo verifies the payment and notifies you.
Quickstart
- Create an account, connect a read-only Binance key and add at least one payment method.
- Create an API key in Dashboard → Developers and keep it on your server.
- Create an invoice for your order and redirect the customer to checkout_url.
- When you receive the invoice.paid webhook, fulfil the order for paid_price_amount.
Authentication
Authenticate every request with your secret API key in the X-Api-Key header. Keys start with cq_live_. Never put a key in browser or mobile-app code — anyone could read it.
X-Api-Key: cq_live_••••••••••••••••••••••••••••••••••••••••••••••••
Create an invoice
Creates a payment request. Every invoice receives a unique amount_to_pay (for example 10.0023) — the extra digits identify the payment, so the customer must send exactly that amount.
| amountrequiredstring | Price as a string, e.g. "10" or "2800.50", in currency. |
| currencystring | Currency of amount: USDT (default), USD, or any 3-letter code you set a rate for, e.g. PKR. See Other currencies. |
| order_idstring | Your order or reference ID. Creating again with the same order_id and amount while the invoice is open returns the same invoice, so retries are safe. |
| descriptionstring | Internal description, visible in your dashboard. |
| customer_emailstring | Optional, for your records. |
| success_urlstring | Where the customer is sent after paying. ?invoice=…&status=paid is appended. |
| cancel_urlstring | Shown as “Cancel and return” on the checkout page. |
| webhook_urlstring | Overrides your default webhook endpoint for this invoice. https only. |
| expires_ininteger | Minutes until the invoice expires (10–1440). Default: 30. |
curl -X POST https://clearqo.com/wp-json/clearqo/v1/invoices \
-H "X-Api-Key: $CLEARQO_KEY" \
-H "Content-Type: application/json" \
-d '{"amount":"10","order_id":"1042","success_url":"https://shop.example/thanks"}'<?php
$ch = curl_init('https://clearqo.com/wp-json/clearqo/v1/invoices');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-Api-Key: ' . getenv('CLEARQO_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['amount' => '10', 'order_id' => '1042']),
]);
$invoice = json_decode(curl_exec($ch), true);
header('Location: ' . $invoice['checkout_url']);const res = await fetch('https://clearqo.com/wp-json/clearqo/v1/invoices', {
method: 'POST',
headers: { 'X-Api-Key': process.env.CLEARQO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: '10', order_id: '1042' }),
});
const invoice = await res.json();
// redirect the customer to invoice.checkout_urlimport os, requests
invoice = requests.post(
'https://clearqo.com/wp-json/clearqo/v1/invoices',
headers={'X-Api-Key': os.environ['CLEARQO_KEY']},
json={'amount': '10', 'order_id': '1042'},
timeout=15,
).json()
# redirect the customer to invoice['checkout_url']Other currencies
If your prices are in another currency, send it as currency. Set your own fixed rate in Dashboard → Settings → Currencies (for example 1 USDT = 285 PKR). The price is converted when the invoice is created — always rounded up to the next cent, so you never receive less — and that rate stays locked for the invoice.
{
"amount": "2800",
"currency": "PKR",
"order_id": "1042"
}
// 1 USDT = 285 PKR → amount: "9.83", amount_to_pay: "9.8323"The invoice object
{
"id": "inv_9f2c4e1a7b3d5c6e8f0a1b2c",
"object": "invoice",
"status": "pending",
"amount": "10.00",
"amount_to_pay": "10.0023",
"currency": "USDT",
"price_amount": "10",
"price_currency": "USD",
"rate": "1",
"order_id": "1042",
"description": "",
"checkout_url": "https://clearqo.com/pay/inv_9f2c4e1a7b3d5c6e8f0a1b2c/",
"methods": [
{
"type": "binance_pay",
"value": "123456789",
"name": "Acme Digital"
},
{
"type": "usdt_trc20",
"value": "TQ\u2026"
},
{
"type": "usdt_bep20",
"value": "0x\u2026"
}
],
"paid_amount": null,
"paid_price_amount": null,
"paid_method": null,
"txid": null,
"created_at": "2026-10-10T12:00:00+00:00",
"expires_at": "2026-10-10T12:30:00+00:00",
"paid_at": null
}| amount_to_paystring | The exact amount the customer must send. |
| methodsarray | Payment methods you enabled, with the Pay ID or address — useful if you build your own payment UI. |
| amountstring | Price converted to USDT (before the unique digits). |
| price_amount · price_currency · ratestring | Your original price, its currency and the locked rate (units of price_currency per 1 USDT). |
| paid_amountstring | null | USDT actually received. |
| paid_price_amountstring | null | What was received, in your price_currency at the locked rate. Credit your customer with this value. |
| paid_methodstring | null | pay, trc20, bep20 or manual. |
| txidstring | null | Binance Pay order ID or blockchain transaction hash. |
Retrieve & list
Returns the current invoice and triggers a fresh check against Binance. Use it to double-check a payment before fulfilling.
Lists invoices, newest first, 50 per page. Optional status filter.
curl https://clearqo.com/wp-json/clearqo/v1/invoices/inv_9f2c4e1a7b3d5c6e8f0a1b2c \ -H "X-Api-Key: $CLEARQO_KEY"
Account
Returns your plan, balance, Binance connection status and enabled methods — handy as a connection test.
Statuses
| pendingstatus | Waiting for the customer to pay. |
| paidstatus | Confirmed on Binance. Safe to fulfil. |
| expiredstatus | Time ran out. An exact late payment within 24 hours still turns it into paid. |
| reviewstatus | A transaction arrived that did not match exactly (e.g. different amount). Approve or reject it in your dashboard. |
| rejectedstatus | You rejected the payment. |
Errors & limits
Errors return a non-2xx status and a JSON body:
{
"code": "clq_balance",
"message": "Merchant balance is too low to accept payments. Please top up.",
"data": { "status": 402 }
}| 400Bad request | Invalid parameters, or no exchange rate set for the currency (clq_no_rate). |
| 401Unauthorized | Missing or invalid API key. |
| 402Payment required | Your balance cannot cover the fee, or your monthly plan limit is reached. |
| 403Forbidden | Account suspended. |
| 404Not found | Invoice does not exist or belongs to another account. |
| 409Conflict | Binance is not connected or no payment method is configured. |
| 429Too many requests | Rate limit: 120 requests per minute per API key. |
Webhooks
Set your endpoint in Dashboard → Developers. We send a POST with a JSON body for these events:
| invoice.paidevent | Payment confirmed — fulfil the order. |
| invoice.expiredevent | The invoice expired without payment. |
| invoice.reviewevent | A non-matching payment needs your decision. |
| invoice.rejectedevent | You rejected a payment. |
| test.pingevent | Sent from the dashboard to test your endpoint. |
{
"id": "evt_3b7c9d2e4f6a8b1c0d2e4f6a",
"type": "invoice.paid",
"created": 1760097600,
"data": { "id": "inv_9f2c…", "status": "paid", "order_id": "1042", "paid_amount": "10.0023", "paid_price_amount": "10.0023", "…": "…" }
}Reply with any 2xx status within 8 seconds. Otherwise we retry after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 24 hours. Events can arrive more than once — process each invoice only once.
Verifying signatures
Every webhook includes X-Clearqo-Signature: t=TIMESTAMP,v1=SIGNATURE, where SIGNATURE = HMAC-SHA256(signing_secret, TIMESTAMP + "." + raw_body) in hex. Always verify it with the raw request body and reject timestamps older than 5 minutes.
<?php
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_CLEARQO_SIGNATURE'] ?? ''), $sig);
$expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $body, getenv('CLEARQO_WEBHOOK_SECRET'));
if (!hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int) ($sig['t'] ?? 0)) > 300) {
http_response_code(400);
exit;
}
$event = json_decode($body, true);
if ($event['type'] === 'invoice.paid') {
// fulfil order $event['data']['order_id'] once, for $event['data']['paid_price_amount']
}
http_response_code(200);const crypto = require('crypto');
app.post('/webhooks/clearqo', express.raw({ type: 'application/json' }), (req, res) => {
const sig = Object.fromEntries((req.get('X-Clearqo-Signature') || '').split(',').map(p => p.split('=')));
const expected = crypto.createHmac('sha256', process.env.CLEARQO_WEBHOOK_SECRET)
.update(sig.t + '.' + req.body).digest('hex');
const valid = sig.v1 && sig.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig.v1), Buffer.from(expected)) &&
Math.abs(Date.now() / 1000 - Number(sig.t)) < 300;
if (!valid) return res.sendStatus(400);
const event = JSON.parse(req.body);
if (event.type === 'invoice.paid') { /* fulfil once */ }
res.sendStatus(200);
});import hmac, hashlib, os, time
def verify(raw_body: bytes, header: str) -> bool:
parts = dict(p.split('=', 1) for p in header.split(',') if '=' in p)
expected = hmac.new(os.environ['CLEARQO_WEBHOOK_SECRET'].encode(),
f"{parts.get('t', '')}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get('v1', '')) and abs(time.time() - int(parts.get('t', 0))) < 300WooCommerce
- Install the Clearqo for WooCommerce plugin and activate it.
- Open WooCommerce → Settings → Payments → Clearqo, enter the platform URL https://clearqo.com, your API key and your webhook signing secret.
- Set your webhook URL in the dashboard to the address shown in the plugin settings.
- For TeraWallet top-ups, set WooCommerce → Settings → General → Number of decimals to 4 so amounts like 10.0023 are credited in full.
Go-live checklist
- Binance key is read-only and IP-restricted (the dashboard shows Connected).
- At least one payment method is configured.
- Your balance covers fees, or a monthly plan is active.
- Webhook signatures are verified and each invoice is fulfilled only once.
- You made a small real payment end-to-end and saw invoice.paid arrive.
Questions? support@clearqo.com