Overview
The PayNex API lets your system talk to our payment products. You can use it to:
Quickstart
Go from zero to your first test payment in four steps.
- 1Get your sandbox keys
Request API access. We send you test keys for the sandbox.
- 2Create a payment or PSID
Call the API from your server with the amount and your order reference.
- 3Let the customer pay
Send them to the checkout URL, or show them the PSID.
- 4Handle the webhook
We call your webhook URL when it is paid. Mark the order as paid.
Authentication
Every request uses your secret key in the Authorization header.
Authorization: Bearer sk_test_your_secret_keyKeep your secret key on your server. Never put it in a website, mobile app or public code. If a key leaks, ask us to replace it.
Your API keys — what works today
Merchants under review get sandbox keys (when our team has sandbox access turned on) in the onboarding portal under Credentials & API. Approved merchants get live and sandbox keys in the merchant portal under Developers. Your secret key is shown once, after you enter your password; if you lose it, rotate it to get a new one (the old one stops working at once).
Today the API runs on the PayNex website at /api/v1. The same address serves sandbox and live — the key prefix decides: sk_test_ is sandbox (test only, no real money, nothing settled) and sk_live_ is live. A sandbox key can never make a live call.
curl https://YOUR-PAYNEX-SITE/api/v1/whoami -H "Authorization: Bearer sk_test_your_secret_key"Status: key checking (GET /api/v1/whoami) is live, and so is the Payments API (/api/v1/payments) for approved merchants who have the online gateway switched on. Its full, always-current documentation is in your merchant portal under Developers → Payments API. The other payment examples further down this page show the planned API for other products. Errors: 401 invalid_api_key, 403 sandbox_disabled / not_approved / suspended / restricted, 429 rate_limited.
Sandbox & live
Build and test in the sandbox with fake money. When you are ready, switch to live keys.
sandbox.api.paynex.pkKeys start with sk_test_. No real money moves.api.paynex.pkKeys start with sk_live_. Real payments.Create a payment POST /payments
Use this for the payment gateway. You get a checkout_url. Send the customer there to pay on the Paynex checkout page.
curl -X POST https://sandbox.api.paynex.pk/v1/payments \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 4750,
"currency": "PKR",
"reference": "ORDER-1042",
"return_url": "https://your-site.com/thank-you"
}'{
"id": "pay_8f2k1x",
"status": "pending",
"amount": 4750,
"currency": "PKR",
"reference": "ORDER-1042",
"checkout_url": "https://checkout.paynex.pk/pay_8f2k1x"
}| Field | Type | Description |
|---|---|---|
amount | integer | Amount in PKR. Required. |
reference | string | Your own order number. Sent back in webhooks. Required. |
return_url | string | Where the customer goes after paying. |
currency | string | Always PKR for now. |
Create a PSID POST /psid
Use this for Paynex invoicing (Option B). You get a PSID number. Show it to your customer. They pay it in their banking app or wallet.
curl -X POST https://sandbox.api.paynex.pk/v1/psid \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 12000,
"due_date": "2026-10-30",
"reference": "FEE-OCT-2041",
"customer": { "name": "Sara Ahmed", "phone": "+923000000000" }
}'{
"psid": "100123456789",
"status": "created",
"amount": 12000,
"due_date": "2026-10-30",
"reference": "FEE-OCT-2041"
}Need a ready page instead? Use the checkout page (Option A). It creates the PSID for you, with no API call needed.
Saved cards POST /charges
For card payments, a customer can save their card on the first payment. You get a card_token (never the card number). Use it to charge them again, for example every month.
curl -X POST https://sandbox.api.paynex.pk/v1/charges \
-H "Authorization: Bearer sk_test_..." \
-d '{ "card_token": "card_tok_4242", "amount": 3500, "reference": "SUB-NOV-0091" }'Webhooks
A webhook is a message we send to your server when something happens. Add your webhook URL in the dashboard. We send a POST request with JSON.
payment.paidA gateway or card payment was successful.payment.failedA payment did not go through.psid.paidThe customer paid a PSID.psid.expiredThe due date passed without payment.
{
"id": "evt_29xk3",
"event": "psid.paid",
"created_at": "2026-10-20T10:42:00+05:00",
"data": {
"psid": "100123456789",
"amount": 12000,
"reference": "FEE-OCT-2041"
}
}Return 200 OK quickly, then do your work.
We may send the same event again. Use the event id to skip duplicates.
If unsure, fetch the payment or PSID from the API.
Verify webhooks
Each webhook has a PayNex-Signature header. Check it with your webhook secret, so you know the message really came from us.
import crypto from "node:crypto";
export function isFromPayNex(rawBody, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}Statuses
Payment
pending → paid or failed
PSID
created → paid or expired
Errors
We use normal HTTP status codes. The body explains what went wrong.
| Code | Meaning | What to do |
|---|---|---|
400 | Bad request | A field is missing or wrong. Check the message. |
401 | Unauthorized | Check your secret key. |
404 | Not found | The payment or PSID does not exist. |
409 | Conflict | The reference was already used. |
5xx | Server error | Try again in a moment. |
Go-live checklist
- Your business is approved by our payment partners
- Secret keys are stored only on your server
- Webhook URL uses HTTPS and checks the signature
- Duplicate webhooks are handled
- You tested paid, failed and expired cases in sandbox
- You switched to live keys
Need help with your integration?
Our team helps you plan, test and go live. Request API access to get sandbox keys and the full API reference.
