Developer Docs

Accept payments with CryptoEze

One API for JazzCash, Easypaisa, QR Payments and USDT (BEP-20). Follow the steps in order. You only need the steps for the methods on your merchant account.

Before you start

  1. Sign in and open Merchant → API keys.
  2. Click Issue secret and copy the Secret key. It is shown once. Keep it on your server only. Never put it in a browser, app, or public code.
  3. Add your Webhook URL on the same page and copy the Webhook signing secret.
Base URLhttps://cryptoeze.com/api/v1
AuthenticationAuthorization: Bearer YOUR_SECRET_KEY
Every create callIdempotency-Key: a-unique-id-per-order
Body formatContent-Type: application/json
Idempotency-Key protects you from double charges

If your server retries the same request with the same key, you get the same payment back, never a second one. Use your order ID.

Redirect checkout

Create the payment, then send your customer to checkout_url. We show the payment page, and bring the customer back to your return_url. Every field in the response sits inside data.

  • No payment screen to build
  • Works for JazzCash, Easypaisa, QR and USDT

Only trust the webhook (or a server-side status check) to mark an order paid. Never trust the customer returning to your page.

Step 1

JazzCash

Amount is in PKR. The customer approves the payment in the JazzCash app.

1. Create the payment

curl -X POST https://cryptoeze.com/api/v1/pkr \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Idempotency-Key: order-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "jazzcash",
    "amount": "1500.00",
    "order_id": "order-1001",
    "customer_email": "buyer@example.com",
    "return_url": "https://your-site.com/thank-you"
  }'

Inside data you get the payment id, status: "pending" and a checkout_url. Send the customer to checkout_url. They enter their JazzCash number there and approve it on their phone.

Step 2

Easypaisa

Exactly the same as JazzCash. Only the method changes.

curl -X POST https://cryptoeze.com/api/v1/pkr \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Idempotency-Key: order-1002" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "easypaisa",
    "amount": "2500.00",
    "order_id": "order-1002",
    "customer_email": "buyer@example.com",
    "return_url": "https://your-site.com/thank-you"
  }'

Send the customer to checkout_url. They approve it in the Easypaisa app.

Step 3

QR Payments

The customer scans a QR with any Pakistani bank app, JazzCash or Easypaisa. No mobile number is needed.

curl -X POST https://cryptoeze.com/api/v1/pkr \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Idempotency-Key: order-1003" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "qr",
    "amount": "999.00",
    "order_id": "order-1003",
    "customer_email": "buyer@example.com",
    "return_url": "https://your-site.com/thank-you"
  }'

Send the customer to checkout_url. We show the QR and the countdown. customer_email is required on every PKR create.

Step 4

USDT BEP-20

Amount is in USDT. The customer sends USDT on BNB Smart Chain (BEP-20) to a unique address for this invoice.

curl -X POST https://cryptoeze.com/api/v1/invoices \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Idempotency-Key: order-1004" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "25.00",
    "order_id": "order-1004",
    "description": "Pro plan",
    "customer_email": "buyer@example.com",
    "return_url": "https://your-site.com/thank-you"
  }'

Inside data you get id, checkout_url, pay_address, send (exact USDT to send) and expires_at. Send the customer to checkout_url. We show the address, QR, amount and live confirmations. CryptoEze users can also pay from their balance with 0 fee.

Good to know

Payments are final after the required confirmations, 15 by default (about a minute). If the customer sends less, the invoice becomes partial. More becomes overpaid. Only official USDT on BEP-20 is ever credited. Other tokens are ignored.

Webhooks

We POST signed JSON to your Webhook URL whenever a payment changes. Answer with HTTP 200; we retry otherwise.

PKR eventspayment.paid · payment.failed · payment.refunded
USDT eventsinvoice.paid · invoice.partial · invoice.expired · invoice.cancelled · invoice.invalid
Signature headerX-CryptoEze-Signature: t=TIMESTAMP,v1=SIGNATURE

Verify the signature (PHP)

$raw    = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_CRYPTOEZE_SIGNATURE'] ?? '';
parse_str(str_replace(',', '&', $header), $p);          // t=…, v1=…

$expected = hash_hmac('sha256', $p['t'] . '.' . $raw, 'YOUR_WEBHOOK_SECRET');
if (! hash_equals($expected, $p['v1'] ?? '') || abs(time() - (int) $p['t']) > 300) {
    http_response_code(400); exit;                          // not from CryptoEze
}

$event = json_decode($raw, true);
if ($event['type'] === 'payment.paid' || $event['type'] === 'invoice.paid') {
    // mark $event['data']['order_id'] as paid, once
}
http_response_code(200);

Verify the signature (Node.js)

const crypto = require('crypto');
// use the RAW request body, not parsed JSON
const parts = Object.fromEntries(header.split(',').map(s => {
  const i = s.indexOf('=');
  return [s.slice(0, i), s.slice(i + 1)];
}));
const expected = crypto.createHmac('sha256', WEBHOOK_SECRET).update(parts.t + '.' + rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 || '');
const ok = a.length === b.length && crypto.timingSafeEqual(a, b)
        && Math.abs(Date.now() / 1000 - Number(parts.t)) <= 300;
Handle each event once

Every event has a unique id. Save it; if the same id arrives again, just answer 200.

Status & errors

Check a PKR paymentGET /api/v1/pkr/ID
Check a USDT invoiceGET /api/v1/invoices/ID
Your balanceGET /api/v1/balance
HTTPCodeWhat to do
400invalid_requestFix the field named in message.
404invalid_requestThat payment or invoice is not on your account.
401authenticationCheck the Bearer secret key.
403forbiddenThis method is not active on your account yet.
409idempotency_conflictSame Idempotency-Key with a different body. Use a new key.
429rate_limitedSlow down and retry after a few seconds.

Go live checklist

  1. Your merchant account is approved for the methods you use.
  2. Your website domain is verified (return URLs must be on it).
  3. Secret key is stored on the server only.
  4. Webhook URL is set, and the signature check passes.
  5. You tested one small payment per method end to end.

Need help? Open Merchant → Support.