API
Authenticate with a merchant secret: Authorization: Bearer sk_live_…. Secrets are hashed at rest and shown once. Keep them on your server — never in HTML, apps, or mobile clients.
Easiest path
- Your server creates an order (secret key).
- Send the customer to
payment_url(or iframeembed_url) — same Pay → I PAID → UTR UI. - Listen for SUCCESS via
status_urlor the signed webhook.
Create order
curl -X POST https://pay.afly.in/api/v1/orders \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ord-10291" \
-d '{"amount":"1500.00","merchant_order_id":"ORD-10291","customer_name":"A. Kabir"}'
Verify payment
Prefer hosted checkout. If you verify from your server, send only the UPI reference. A UTR that was already claimed returns ref_already_claimed — “This UTR is already used.”
curl -X POST https://pay.afly.in/api/v1/payments/verify \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"order_id":"ORD-AB12CD","upi_ref":"129211813480"}'
Create-order also returns upi_uri (amount locked), payment_url, embed_url (iframe), and status_url.
Server SDK
<?php
require "voltpay.php";
$vp = new VoltPay("https://pay.afly.in", getenv("VOLTPAY_SECRET"));
$order = $vp->createOrder(["amount" => "10.00", "merchant_order_id" => "SKU-10"], "SKU-10");
header("Location: " . $order["payment_url"]);
Payment status
curl https://pay.afly.in/api/v1/orders/ORD-AB12CD \ -H "Authorization: Bearer sk_live_xxx"
Webhook
On success VoltPay POSTs JSON to your URL with header X-VoltPay-Signature: t=TIMESTAMP,v1=HMAC_SHA256(secret, timestamp + '.' + body).
{
"event": "payment.success",
"data": {
"order_id": "ORD-10291",
"amount": "1500.00",
"upi_ref": "129211813480",
"status": "SUCCESS"
}
}
cURL example
<?php
$ch = curl_init("https://pay.afly.in/api/v1/orders");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . $secret,
"Content-Type: application/json",
"Idempotency-Key: " . $merchantOrderId,
],
CURLOPT_POSTFIELDS => json_encode([
"amount" => "1500.00",
"merchant_order_id" => $merchantOrderId,
]),
CURLOPT_RETURNTRANSFER => true,
]);
$order = json_decode(curl_exec($ch), true);
// Redirect customer to $order["data"]["payment_url"]
Device ingest
The Android listener sends the raw notification. The server parses it. Pair with a 6-digit code from the merchant dashboard, then:
POST https://pay.afly.in/api/v1/device/ingest
Authorization: Bearer dt_…
{"raw_message":"Rs. 1,500 received in Slice A/c xx4210 ... (Ref ID: 129211813480).","package":"slice"}