Developers

API reference

Create UPI payments for your own Paytm Business account and get told when they're paid. Your API key and secret are on Paytm & API keys after you sign in.

Nanofox SMM panels

No code needed. In your panel open Admin → Payment gateways → + Nanofox Pay, paste your API key and secret, and press Save. The panel checks the keys, then shows customers a QR on Add funds and adds the money automatically.

Authentication

Base URL: https://gateway.nanofox.in/api/v1/. Every request carries three headers. The signature proves the request came from you and can't be replayed later (requests more than 5 minutes off are refused).

HeaderValue
X-Api-KeyYour API key (nfk_…)
X-TimestampCurrent Unix time in seconds
X-SignatureHex HMAC-SHA256 with your API secret over timestamp.METHOD.path.body

path is the path with its query string, e.g. /api/v1/payments.php?id=NFP…. For GET the body is empty.

// PHP
$ts   = (string) time();
$path = '/api/v1/payments.php';
$body = json_encode(['order_id' => 'INV-1042', 'amount' => 499]);
$sig  = hash_hmac('sha256', "$ts.POST.$path.$body", $apiSecret);
// send headers X-Api-Key, X-Timestamp: $ts, X-Signature: $sig
// Node.js
const ts = String(Math.floor(Date.now() / 1000));
const sig = crypto.createHmac('sha256', apiSecret)
  .update(`${ts}.POST.${path}.${body}`).digest('hex');

POST Create a payment

/api/v1/payments.php with a JSON body. Sending the same order_id again returns the same payment, so retries are safe.

FieldTypeNotes
order_idstringYour reference, 3–64 letters, numbers, _ or -
amountnumberRupees, 1 to 2,00,000
webhook_urlstringOptional. Public http(s) address; defaults to the one saved on your account
// 201 Created  (200 with "existing": true for a repeated order_id)
{ "ok": true, "existing": false,
  "payment_id": "NFP4F2A…", "order_id": "INV-1042", "amount": 499,
  "status": "PENDING", "paid_amount": null, "utr": null, "paytm_txn_id": null,
  "upi_link": "upi://pay?pa=…&am=499.00&tr=NFP4F2A…&cu=INR",
  "created_at": "…", "expires_at": "…", "paid_at": null }

Show upi_link as a QR code (and as a button on phones). Customers can pay with any UPI app.

GET Get a payment

/api/v1/payments.php?id=NFP… or ?order_id=…. A payment that is still waiting is checked with Paytm right away (at most once every 2 seconds). Returns the same fields as above.

GET Test your keys

/api/v1/ping.php checks your keys and plan and tells you whether your Paytm details are saved.

{ "ok": true, "merchant": 12, "plan_until": "2026-12-01 10:00:00", "paytm_ready": true }

Webhooks

When a payment is confirmed we POST JSON to its webhook address: the payment fields plus "event": "payment.success" (or payment.underpaid). Headers:

X-Nanofox-TimestampUnix time in seconds
X-Nanofox-SignatureHex HMAC-SHA256 with your API secret over timestamp.body

Answer with any 2xx code. Otherwise we retry after 1, 2, 5, 15 and 30 minutes, then 1, 3 and 6 hours. Always confirm with GET before giving value, and ignore webhooks with an old timestamp.

// PHP: check a webhook
$raw = file_get_contents('php://input');
$ts  = $_SERVER['HTTP_X_NANOFOX_TIMESTAMP'] ?? '';
$ok  = abs(time() - (int) $ts) < 600 && hash_equals(
         hash_hmac('sha256', "$ts.$raw", $apiSecret),
         $_SERVER['HTTP_X_NANOFOX_SIGNATURE'] ?? '');

Statuses

Pending PENDINGWaiting for the customer to pay
Paid SUCCESSPaid in full (or more) — give value
Underpaid UNDERPAIDPaid, but less than the amount; paid_amount says how much
Expired EXPIREDThe QR time ran out. Still re-checked for 48 hours, so it can become SUCCESS later

Errors

Errors return {"ok": false, "error": "…", "message": "…"}.

HTTPerrorMeaning
400jsonThe body is not JSON
401auth · clockWrong key or signature · your server clock is more than 5 minutes off
402planNo active plan — renew to continue
404not_foundNo such payment on your account
409order_idThis order ID was already used with a different amount
422paytm · order_id · amount · webhook_urlPaytm details missing, or a field is not valid
429rateToo many requests this minute (120 new payments, 600 status checks)