QuickPay is a hosted crypto payment API. Send your customer to a QuickPay-hosted payment page, and poll for confirmation — no wallets, no node infrastructure required on your side. All amounts are denominated in USD; QuickPay handles the crypto conversion in real time.
Base URL: https://4376hdfdaf.shop
Invoice creation requires an API key passed via the X-API-Key request header.
Keys are issued per project from the admin panel. Status and cancel endpoints are unauthenticated.
X-API-Key: qp_a1b2c3d4e5f6...
Creates a new payment invoice and redirects to the hosted payment page. The payment page displays the crypto address and amount your customer needs to send.
| Name | Type | Description |
|---|---|---|
| X-API-Key required | string | Your project API key. |
| Field | Type | Description |
|---|---|---|
| coin required | string | Cryptocurrency to accept. One of: eth, btc, usdt, usdc. |
| amount required | float | Invoice amount in USD (e.g. 49.99). Must be between 0.01 and 999,999. |
| callback_url | string | HTTPS URL to POST a webhook to when the invoice is confirmed. Must start with http:// or https://. See Webhooks. |
| metadata | string | Arbitrary string (e.g. a user ID or JSON blob) passed through unchanged in the webhook payload. Max use: identifying which user to upgrade. |
303 Redirect to /invoice/{tx_id} on success.
Returns JSON error on invalid coin, amount, or missing/revoked API key.
curl -X POST https://4376hdfdaf.shop/create-invoice \ -H "X-API-Key: qp_a1b2c3d4e5f6..." \ -F "coin=eth" \ -F "amount=49.99"
const body = new FormData();
body.append("coin", "eth");
body.append("amount", "49.99");
const resp = await fetch("https://4376hdfdaf.shop/create-invoice", {
method: "POST",
headers: { "X-API-Key": "qp_a1b2c3d4e5f6..." },
body,
redirect: "follow",
});
// resp.url will be the hosted payment page — redirect your user there
window.location.href = resp.url;
Returns the hosted HTML payment page for an invoice. Customers are automatically redirected here
after POST /create-invoice. The page shows the deposit address, expected crypto amount,
a live countdown to expiry, and auto-refreshes status every few seconds.
| Parameter | Type | Description |
|---|---|---|
| tx_id required | string | The invoice ID returned from POST /create-invoice. |
200 HTML payment page, or 404 JSON if the invoice does not exist.
Returns the current status of an invoice as JSON. Poll this endpoint to detect payment confirmation on your backend without relying on the hosted payment page.
| Parameter | Type | Description |
|---|---|---|
| tx_id required | string | The invoice ID. |
{
"status": "confirmed",
"confirmations": 12,
"required_confirmations": 12,
"tx_hash": "0xabc123..."
}
curl https://4376hdfdaf.shop/status/3f2e1a...
async function waitForConfirmation(txId) {
while (true) {
const resp = await fetch(`https://4376hdfdaf.shop/status/${txId}`);
const data = await resp.json();
if (data.status === "confirmed") {
console.log("Payment confirmed:", data.tx_hash);
break;
}
if (data.status === "expired" || data.status === "cancelled") {
console.log("Invoice ended:", data.status);
break;
}
await new Promise(r => setTimeout(r, 5000)); // poll every 5s
}
}
Cancels a pending invoice and frees the deposit address. Only pending invoices can be cancelled —
invoices that are detected, confirmed, or expired cannot be changed.
| Parameter | Type | Description |
|---|---|---|
| tx_id required | string | The invoice ID to cancel. |
{ "status": "cancelled" }
{ "error": "Cannot cancel a confirmed invoice" }
Pass a callback_url when creating an invoice and QuickPay will
POST a signed JSON payload to that URL the moment the invoice
status changes to confirmed. Use this to trigger server-side
actions — like upgrading a user's account — without polling.
QuickPay sends a JSON body with the following fields:
{
"tx_id": "3f2e1a...",
"status": "confirmed",
"coin": "eth",
"amount": 49.99,
"tx_hash": "0xabc123...",
"confirmations": 12,
"metadata": "user_id=abc123"
}
Every webhook request includes an X-QuickPay-Signature header
of the form sha256=<hex>. The signature is an
HMAC-SHA256 of the raw request body using your project's webhook secret (visible on the admin key detail page).
Always verify this before acting on a webhook.
import hmac, hashlib
WEBHOOK_SECRET = "whsec_..." # from admin panel
def verify(raw_body: bytes, signature_header: str) -> bool:
expected = "sha256=" + hmac.new(
WEBHOOK_SECRET.encode(),
raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature_header)
# FastAPI / Starlette example
from fastapi import Request, HTTPException
@app.post("/webhooks/quickpay")
async def handle_webhook(request: Request):
body = await request.body()
sig = request.headers.get("X-QuickPay-Signature", "")
if not verify(body, sig):
raise HTTPException(status_code=400, detail="Invalid signature")
data = await request.json()
if data["status"] == "confirmed":
user_id = data.get("metadata") # e.g. "user_id=abc123"
# upgrade user here
return {"ok": True}
const crypto = require("crypto");
const WEBHOOK_SECRET = "whsec_..."; // from admin panel
app.post("/webhooks/quickpay", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.headers["x-quickpay-signature"] ?? "";
const expected = "sha256=" + crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(400).send("Invalid signature");
}
const data = JSON.parse(req.body);
if (data.status === "confirmed") {
// upgrade user using data.metadata
}
res.json({ ok: true });
});
Important: use hmac.compare_digest /
crypto.timingSafeEqual — never a plain string comparison —
to prevent timing attacks. After verifying, also call
GET /status/{tx_id} from your server to independently
confirm the status before granting access.
An invoice moves through the following states:
| Status | Meaning | |
|---|---|---|
| pending | Invoice created, waiting for an on-chain transaction to appear. | |
| detected | A matching transaction was found on-chain but has not yet reached the required confirmation count. | |
| confirmed | Sufficient confirmations received. Payment is complete. | |
| expired | The invoice expiry window passed with no payment detected. | |
| cancelled | Manually cancelled via POST /invoice/{tx_id}/cancel. |
|
| Value | Name | Network | Confirmations required |
|---|---|---|---|
| eth | Ethereum | Ethereum mainnet | 12 |
| btc | Bitcoin | Bitcoin mainnet | 1 |
| usdt | Tether | Ethereum (ERC-20) | 6 |
| usdc | USD Coin | Ethereum (ERC-20) | 6 |
Prices are fetched from CoinGecko and cached for 60 seconds. A ±1% tolerance (capped at $0.10) is applied to the expected crypto amount to account for rounding and minor price movement between invoice creation and payment.