Everything you need to integrate UPI payment verification into your product. Base URL: https://api.upisignal.com/v1
All requests must include your API key in the Authorization header as a Bearer token. Use sk_test_ keys in development and sk_live_ keys in production.
Authorization: Bearer sk_test_your_key_hereCreates a dynamic UPI QR code tied to a specific amount and order. The QR returns a PNG image URL and a UPI deep link.
/v1/qr/generate| Field | Type | Description |
|---|---|---|
| amount | integer | Amount in paise (₹1 = 100). Required. |
| order_id | string | Your unique order identifier. Required. |
| upi_id | string | Your UPI ID to receive the payment. Required. |
| expires_in | integer | Seconds until QR expires. Default: 300. |
| note | string | Merchant note shown in UPI apps. Optional. |
curl -X POST https://api.upisignal.com/v1/qr/generate \
-H "Authorization: Bearer sk_test_••••••••" \
-H "Content-Type: application/json" \
-d '{
"amount": 49900,
"order_id": "order_abc123",
"upi_id": "you@paytm",
"expires_in": 300
}'{
"id": "qr_01HXYZ",
"qr_url": "https://api.upisignal.com/qr/qr_01HXYZ.png",
"upi_link": "upi://pay?pa=you@paytm&am=499.00&tn=order_abc123",
"amount": 49900,
"status": "active",
"expires_at": "2025-01-15T10:37:44Z"
}Poll this endpoint to check if a payment was received for a given order ID. UPISignal also fires a webhook automatically — you don't need to poll if you have a webhook configured.
/v1/payments/verify| Field | Type | Description |
|---|---|---|
| order_id | string | The order ID used when generating the QR. |
{
"payment_id": "pay_01HABC",
"order_id": "order_abc123",
"status": "success",
"amount": 49900,
"upi_ref": "402512345678",
"payer_vpa": "customer@paytm",
"verified_at": "2025-01-15T10:32:40Z"
}UPISignal delivers signed POST requests to your endpoint when payment events occur. Every payload includes an X-UPISignal-Signature header for verification.
payment.successPayment verified successfullypayment.failedQR expired without a paymentpayment.pendingPayment detected, awaiting confirmationqr.expiredQR passed its expiry timeimport crypto from "crypto";
export function verifyWebhook(
rawBody: string,
signature: string
): boolean {
const expected = crypto
.createHmac("sha256", process.env.UPISIGNAL_WEBHOOK_SECRET!)
.update(rawBody)
.digest("hex");
return `sha256=${expected}` === signature;
}
// In your route handler:
app.post("/webhook", express.raw({ type: "*/*" }), (req, res) => {
const sig = req.headers["x-upisignal-signature"] as string;
if (!verifyWebhook(req.body.toString(), sig)) {
return res.status(400).send("Invalid signature");
}
const event = JSON.parse(req.body.toString());
if (event.event === "payment.success") {
// fulfil the order
}
res.sendStatus(200);
});/v1/qr/generateGenerate a dynamic UPI QR code/v1/qr/:idFetch a QR code and its current status/v1/payments/verifyManually verify a payment by order ID/v1/paymentsList all payments with filters/v1/payments/:idFetch a single payment record/v1/webhooksRegister a webhook endpoint/v1/webhooks/:idRemove a webhook endpoint