PayGate API

Base URL https://pay.mawanta.com/v1 · HTTP Basic auth with key_id:key_secret · amounts in paise (₹1 = 100) · JSON.

1. Create an order (server-side)

curl -u KEY_ID:KEY_SECRET https://pay.mawanta.com/v1/orders \
  -H 'Content-Type: application/json' \
  -d '{"amount": 49900, "currency": "INR", "receipt": "rcpt_1001", "notes": {"cart": "42"}}'

2. Open checkout (browser)

<script src="https://pay.mawanta.com/checkout.js"></script>
<script>
new PayGate({
  order_id: "order_xxxxxxxx",            // from step 1
  handler: function (r) {                // success: send r to YOUR server
    // r.paygate_payment_id, r.paygate_order_id, r.paygate_signature
    fetch('/verify', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(r)});
  },
  onfailed: function (r) { alert('Payment failed'); }
}).open();
</script>

Or redirect the customer to https://pay.mawanta.com/checkout/ORDER_ID. Pass callback_url when creating the order to get the result POSTed back to your server (fields: paygate_payment_id, paygate_order_id, paygate_signature, paygate_status).

3. Verify the signature (server-side — mandatory)

// Node.js
const expected = crypto.createHmac('sha256', KEY_SECRET).update(order_id + '|' + payment_id).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(paygate_signature))) reject();

// PHP
$expected = hash_hmac('sha256', $order_id.'|'.$payment_id, $KEY_SECRET);
if (!hash_equals($expected, $signature)) reject();

# Python
expected = hmac.new(KEY_SECRET.encode(), f"{order_id}|{payment_id}".encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature): reject()

4. Webhooks

Set the endpoint in Dashboard → Webhooks. Each POST has headers X-PayGate-Signature = HMAC-SHA256(raw body, webhook secret), X-PayGate-Event-Id (use for idempotency). Respond with any 2xx. Events: payment.captured, payment.failed, order.paid, refund.processed. Retries: 1m, 5m, 30m, 2h, 6h, 12h.

{"entity":"event","event":"payment.captured","mode":"live","payload":{"payment":{"id":"pay_...","amount":49900,"status":"captured","order_id":"order_...","method":"upi", ...}}}

Endpoints

POST/v1/ordersamount*, currency, receipt, notes, callback_url, email, contact
GET/v1/orders · /v1/orders/:id · /v1/orders/:id/paymentsfetch / list (count, skip)
GET/v1/payments · /v1/payments/:idfetch / list
POST/v1/payments/:id/refundamount (optional, paise; default full), notes
GET/v1/refunds · /v1/refunds/:id
POST/v1/payment_linksamount*, description, reusable
GET/v1/payment_links
POST/v1/payment_links/:id/cancel
GET/v1/settlements

Test mode

Test keys (pg_test_…) use a simulated bank: card 4111 1111 1111 1111 succeeds, 4000 0000 0000 0002 is declined, 4000 0000 0000 9995 insufficient funds; UPI success@paygate / failure@paygate; netbanking & wallets open a page where you choose success or failure. No real money moves.

Errors

HTTP 400  {"error":{"code":"BAD_REQUEST_ERROR","description":"amount must be an integer in paise, minimum 100 (₹1)","field":"amount"}}
HTTP 401  bad credentials · 403 live not activated / suspended · 404 not found · 429 rate limited