Overview & Architecture
آرکیٹیکچر کا جائزہ
The Checktion Payment Gateway provides a unified REST API to accept payments via JazzCash MWALLET and EasyPaisa MA — two of Pakistan's most widely used mobile wallets. Both share the same two-step flow: first create a payment intent, then charge the customer's wallet.
Checktion Payment Gateway آپ کو JazzCash اور EasyPaisa دونوں موبائل والٹ سے ایک ہی API کے ذریعے ادائیگی قبول کرنے کی سہولت دیتا ہے۔ پہلے پیمنٹ بنائیں، پھر کسٹمر کا والٹ چارج کریں — یہ دو آسان مراحل ہیں۔
Two-Step Payment Flow — دو مرحلوں کا عمل
Create Payment Intent
Send payment details to Checktion. Get a flow_id in return. This is your session token.
POST /auth/
پیمنٹ بنائیں اور flow_id حاصل کریں
Charge the Wallet
Submit the flow_id along with the customer's mobile number to charge their wallet.
POST /auth/jazzcash-charge/
POST /auth/easypaisa-charge/
POST /auth/oneqr/
کسٹمر کا موبائل نمبر دے کر والٹ چارج کریں
Check Status (if needed)
If payment is still processing, poll the inquiry endpoint until a final status is returned.
POST /inquire/v1/
پیمنٹ کی حیثیت چیک کریں
Only fulfill when status: "completed" is confirmed. Never on "processing".
صرف "completed" ملنے پر آرڈر پورا کریں — "processing" پر نہیں
Always append a trailing slash to every endpoint URL. Requests to /auth (without slash) will fail. Use /auth/, /auth/jazzcash-charge/, /auth/easypaisa-charge/, /auth/oneqr/, and /inquire/v1/
ہر endpoint URL کے آخر میں slash (/) لگانا ضروری ہے — بغیر slash کے request کام نہیں کرے گی
Authentication & Signature
تصدیق اور HMAC دستخط
Every API request is authenticated using an HMAC-SHA256 signature. You build a pipe-separated string from specific fields, then sign it with your secret merchant_api_key. The signature formula differs for each endpoint.
ہر API request کو آپ کی secret key سے HMAC-SHA256 الگورتھم سے sign کیا جاتا ہے۔ sign string مختلف fields کو "|" سے جوڑ کر بنائی جاتی ہے۔ یہ key کبھی بھی frontend پر expose نہ کریں — یہ ہمیشہ آپ کے server پر رہنی چاہیے۔
Signature Formulas — دستخط کے فارمولے
// ── Step 1: Create Payment (/auth/) ──────────────────────────────
$sign_string = "merchant_mid|amount|currency|web_id|payer_email|timestamp";
// amount must be formatted as 2 decimal places: "1999.99" not "2000"
// ── Step 2a: JazzCash Charge (/auth/jazzcash-charge/) ────────────
$sign_string = "merchant_mid|flow_id|mobile_number|timestamp";
// ── Step 2b: EasyPaisa Charge (/auth/easypaisa-charge/) ──────────
$sign_string = "merchant_mid|flow_id|mobile_number|timestamp";
// Same formula as JazzCash charge
// ── Step 2c: OneQR Generate (/auth/oneqr/) ────────────────────────
$sign_string = "merchant_mid|flow_id|timestamp";
// No mobile_number — OneQR generates a scannable QR, no wallet number needed
// ── Step 3: Status Inquiry (/inquire/v1/) — Single ───────────────
$sign_string = "merchant_mid|flow_id|timestamp";
// ── Step 3: Status Inquiry (/inquire/v1/) — Batch ────────────────
$sorted_ids = sort(["id3", "id1", "id2"]); // alphabetically
$sign_string = "merchant_mid|id1,id2,id3|timestamp";
// comma-joined, no spaces
// ── Final Step: Compute Signature (same for all) ─────────────────
$signature = hash_hmac("sha256", $sign_string, $merchant_api_key);
Never expose your merchant_api_key in frontend JavaScript, mobile apps, or client-side code. Always compute the signature on your server. The timestamp must be within ±10 minutes of server time.
merchant_api_key کبھی بھی frontend یا موبائل app میں نہ رکھیں۔ Signature ہمیشہ اپنے server سے بنائیں۔ Timestamp ±10 منٹ کے اندر ہونا چاہیے۔
Step 1 — Create Payment
پہلا مرحلہ — پیمنٹ بنائیں
Before charging any wallet, you must create a payment intent. This endpoint registers the payment in the Checktion system and returns a flow_id — a 32-character hex token you'll use in Step 2.
کوئی بھی والٹ چارج کرنے سے پہلے، /auth/ endpoint پر پیمنٹ بنانا ضروری ہے۔ یہ آپ کو flow_id دیتا ہے جو اگلے مرحلے میں استعمال ہوگا۔
POST /auth/ — Request Body
{
"merchant_mid": "MID-ABC123XYZ", // Your Merchant ID
"amount": 1999.99, // PKR amount (number, not string)
"currency": "PKR", // Must be "PKR"
"payer_email": "buyer@example.com", // Customer email address
"web_id": "ORDER-20250315-001", // Your unique order reference
"return": "https://yoursite.com/success", // Callback URL
"timestamp": 1739683200, // Unix timestamp (seconds)
"signature": "a3f1c8d2e4b09fa7..." // HMAC-SHA256 (see Section 2)
}
Request Fields — درخواست کے فیلڈز
| Field | Type | Required | Description / وضاحت |
|---|---|---|---|
merchant_mid | string | Required | Your merchant identifier, e.g. MID-ABC123XYZ — آپ کا Merchant ID |
amount | number | Required | Amount in PKR. Formatted as 2 decimal places internally — ادائیگی کی رقم |
currency | string | Required | Must be "PKR" — صرف PKR قبول ہوگا |
payer_email | string | Required | Valid email address of the customer — کسٹمر کا ای میل |
web_id | string | Required | Unique order reference (max 100 chars). Duplicate rejected with HTTP 409 — آپ کا منفرد آرڈر نمبر |
return | string | Required | Callback URL after payment. Domain must match registered merchant domain — کامیابی کے بعد redirect URL |
timestamp | integer | Required | Current Unix timestamp in seconds. Within ±10 minutes — موجودہ وقت |
signature | string | Required | HMAC-SHA256 signature — see Section 2 — HMAC دستخط |
Success — HTTP 201
{
"status": "ok",
"flow_id": "a3f1c8d2e4b09fa72c1d...",
"payment_url": "https://checktion.com/pay/a3f1c8d2e4b09fa72c1d8e3f5b607a91",
"web_id": "ORDER-20250315-001"
}
Use flow_id in Step 2 (API charge). If you prefer hosted checkout, redirect the customer to payment_url and confirm completion using IPN or /inquire/v1/.
Common Errors
| HTTP | Error Message |
|---|---|
| 400 | Required fields missing |
| 400 | Invalid or expired timestamp |
| 401 | Invalid merchant_mid / signature |
| 403 | Merchant not active / domain mismatch |
| 409 | Duplicate web_id for this merchant |
Hosted Checkout Redirect — /pay/<flow_id>
If you do not want to collect the customer's mobile number on your side, redirect the user to the Checktion hosted checkout page. This page handles the UI flow and then redirects the customer back to your return URL.
اگر آپ کسٹمر کا موبائل نمبر خود collect نہیں کرنا چاہتے، تو Checktion hosted checkout استعمال کریں۔ کسٹمر کو /pay/<flow_id> پر redirect کریں اور بعد میں IPN یا /inquire/v1/ سے status confirm کریں۔
The return URL redirect is only for customer experience. Always confirm the final result using IPN (recommended) or /inquire/v1/ before fulfilling the order.
صرف browser redirect پر بھروسہ نہ کریں۔ آرڈر صرف IPN یا /inquire/v1/ سے "completed" confirm ہونے کے بعد ہی پورا کریں۔
Step 2A — Charge JazzCash Wallet
جاز کیش والٹ چارج کریں
This endpoint directly contacts the JazzCash MWALLET gateway. The response is immediate — either completed (HTTP 200, funds deducted) or processing (HTTP 202, customer receives a USSD/push prompt and must confirm).
یہ endpoint براہ راست JazzCash gateway سے رابطہ کرتا ہے۔ جواب فوری ملتا ہے — یا تو ادائیگی مکمل ہوجاتی ہے یا کسٹمر کو تصدیق کا پیغام جاتا ہے۔
POST /auth/jazzcash-charge/ — Request Body
{
"merchant_mid": "MID-ABC123XYZ",
"flow_id": "a3f1c8d2e4b09fa72c1d8e3f5b607a91", // from /auth/
"mobile_number": "03001234567", // 11 digits, starts with 03
"timestamp": 1739683260,
"signature": "d7e2f3a1b4c5..." // HMAC of mid|flow_id|mobile|timestamp
}
Payment deducted immediately — رقم مل گئی
{
"success": true,
"status": "completed",
"message": "Payment completed successfully",
"amount": "1999.99",
"currency": "PKR",
"transaction_id": "202604031350558459...",
"ref_no": "T2026040308505404371d"
}
Customer must confirm on phone — /inquire/v1/ سے status چیک کریں
{
"success": true,
"status": "processing",
"message": "Payment in processing",
"amount": "1999.99",
"currency": "PKR",
"transaction_id": "202604031350558459...",
"ref_no": "T2026040308505404371d"
}
JazzCash-Specific Errors
| HTTP | Error | Action |
|---|---|---|
| 400 | Transaction declined - Insufficient balance | Notify customer. Do not retry with same flow_id. |
| 400 | Invalid mobile_number format | Validate phone (03XXXXXXXXX) before submitting |
| 404 | Payment not found or not pending | Create new payment via /auth/ |
| 410 | Payment has expired | Create new payment via /auth/ |
If /auth/jazzcash-charge/ returns HTTP 400 (failed), do not retry with the same flow_id. You must go back to Step 1 and create a new payment via /auth/.
اگر payment ناکام ہو جائے تو وہی flow_id دوبارہ استعمال نہ کریں — نئی payment بنانے کے لیے /auth/ پر واپس جائیں۔
Step 2B — Charge EasyPaisa Wallet
ایزی پیسہ والٹ چارج کریں
This endpoint sends a payment request to the customer's EasyPaisa account. The customer receives an SMS/app notification to confirm. A successful initiation returns HTTP 202 with status "processing". HTTP 200 is only returned when the payment is fully PAID — matching JazzCash behaviour. Poll /inquire/v1/ to confirm completion.
یہ endpoint کسٹمر کے EasyPaisa account کو notify کرتا ہے۔ کسٹمر کو SMS/app notification ملتی ہے۔ شروعات پر HTTP 202 ملتا ہے — HTTP 200 صرف اس وقت آتا ہے جب رقم مکمل ادا ہو جائے، بالکل JazzCash کی طرح۔
POST /auth/easypaisa-charge/ — Request Body
{
"merchant_mid": "MID-ABC123XYZ",
"flow_id": "a3f1c8d2e4b09fa72c1d8e3f5b607a91", // from /auth/
"mobile_number": "03001234567", // EasyPaisa-registered number
"timestamp": 1739683260,
"signature": "d7e2f3a1b4c5..." // HMAC of mid|flow_id|mobile|timestamp
}
Payment confirmed — funds received
{
"success": true,
"status": "completed",
"message": "Payment completed successfully",
"gateway": "easypaisa",
"amount": "1999.99",
"currency": "PKR",
"transaction_id": "48836361137",
"ref_no": "VLX20260403140523abc123"
}
SMS/notification sent — /inquire/v1/ سے status چیک کریں
{
"success": true,
"status": "processing",
"message": "Payment request sent. Please check your EasyPaisa app / SMS and confirm.",
"gateway": "easypaisa",
"amount": "1999.99",
"currency": "PKR",
"transaction_id": "VLX20260403140523abc123",
"ref_no": "VLX20260403140523abc123"
}
Both gateways now share the same HTTP code contract: HTTP 200 = payment completed, HTTP 202 = processing. EasyPaisa initiation returns HTTP 202, and only fires HTTP 200 when the IPN confirms a PAID status. You must poll /inquire/v1/ after a 202 to confirm completion.
اب دونوں gateways کا HTTP code ایک جیسا ہے: HTTP 200 = رقم مل گئی، HTTP 202 = کسٹمر کی تصدیق کا انتظار ہے۔ EasyPaisa شروع میں HTTP 202 دیتا ہے اور HTTP 200 صرف PAID ہونے پر آتا ہے۔
Step 2C — Generate OneQR Code
OneQR کوڈ بنائیں
Unlike JazzCash and EasyPaisa charge, OneQR does not push a request to a customer's mobile number. Instead this endpoint generates a scannable QR code tied to the payment. The customer scans it with any QR-enabled banking or wallet app to complete payment. No mobile_number field is required.
JazzCash اور EasyPaisa کے برعکس، OneQR کسٹمر کے موبائل نمبر پر درخواست نہیں بھیجتا۔ یہ endpoint ایک اسکین کے قابل QR کوڈ بناتا ہے۔ موبائل نمبر درکار نہیں۔
POST /auth/oneqr/ — Request Body
{
"merchant_mid": "MID-ABC123XYZ",
"flow_id": "a3f1c8d2e4b09fa72c1d8e3f5b607a91", // from /auth/
"timestamp": 1739683260,
"signature": "a1b2c3d4..." // HMAC of mid|flow_id|timestamp
}
Signature Formula — دستخط کا فارمولا
$sign_string = "merchant_mid|flow_id|timestamp";
$signature = hash_hmac("sha256", $sign_string, $merchant_api_key);
Response: QR Generated — HTTP 200
{
"success": true,
"status": "processing",
"gateway": "oneqr",
"qr_string": "00020101021226580014PK.COM.ONEQR...",
"psid": "PSID20260403140523",
"ref_no": "VLX20260403140523oneqr",
"amount": "1999.99",
"currency": "PKR"
}
Render qr_string as a QR image for the customer to scan. Poll /inquire/v1/ using flow_id.
OneQR Response Fields
| Field | Type | Description / وضاحت |
|---|---|---|
success | boolean | Whether the QR was generated successfully |
status | string | "processing" — awaiting customer scan & confirmation |
gateway | string | Always "oneqr" |
qr_string | string | Raw QR payload — render as QR code image |
psid | string | Payment Session ID assigned by OneQR |
ref_no | string | Checktion reference number for this transaction |
amount | string | Amount as 2-decimal string |
currency | string | Always "PKR" |
OneQR-Specific Errors
| HTTP | Error | Action |
|---|---|---|
| 400 | Required fields missing | Validate request body |
| 401 | Invalid merchant_mid / signature | Recheck HMAC formula: mid|flow_id|timestamp |
| 404 | Payment not found or wrong merchant | Create new payment via /auth/ |
| 410 | Payment has expired | Create new payment via /auth/ |
Because OneQR is scan-based rather than push-based, a successful call always returns HTTP 200 with status "processing". You must poll /inquire/v1/ — or listen for IPN — until the status becomes completed.
OneQR "push" کی بجائے "scan" پر مبنی ہے، اس لیے کامیاب کال ہمیشہ HTTP 200 اور status: "processing" دیتی ہے۔ آرڈر مکمل کرنے سے پہلے /inquire/v1/ سے "completed" کنفرم کریں یا IPN کا انتظار کریں۔
Payment Status Values
ادائیگی کی حیثیت کی اقدار
| Status | Code | Meaning | Next Action |
|---|---|---|---|
| completed | 200 | Payment successfully completed and funds received — ادائیگی مکمل، رقم مل گئی | ✅ Fulfill the order |
| processing | 101 | Being processed — awaiting customer action — کسٹمر کے تصدیق کا انتظار | ⏳ Poll /inquire/v1/ |
| pending | 100 | Payment created, not yet submitted to gateway — پیمنٹ بنی، چارج نہیں ہوئی | Proceed to charge endpoint |
| failed | 400 | Payment attempt failed — ادائیگی ناکام رہی | Create new payment via /auth/ |
| expired | 102 | Payment expired (25-minute window passed) — پیمنٹ کی مدت ختم | Create new payment via /auth/ |
| cancelled | 103 | Cancelled by customer or gateway — کسٹمر یا gateway نے منسوخ کیا | Create new payment if needed |
| refunded | 106 | Amount returned to customer — رقم واپس کی گئی | Update order status |
| dropped | 401 | Payment abandoned midway — ادائیگی ادھوری چھوڑ دی | Treat as failed |
Check Payment Status
ادائیگی کی حیثیت چیک کریں
Query the current status of any payment at any time. Look up by flow_id or web_id. Supports single and batch lookups (up to 50 IDs).
کسی بھی وقت /inquire/v1/ سے payment کی حیثیت معلوم کریں — flow_id یا web_id سے۔ ایک ساتھ 50 تک IDs بھیج سکتے ہیں۔
{
"merchant_mid": "MID-ABC123XYZ",
"flow_id": "a3f1c8d2e4b09fa72c1d8e3f5b607a91",
"timestamp": 1739683320,
"signature": "e9a2b3c4..." // HMAC of mid|flow_id|timestamp
}
{
"merchant_mid": "MID-ABC123XYZ",
"web_id": "ORDER-20250315-001", // Use EITHER flow_id OR web_id, not both
"timestamp": 1739683320,
"signature": "f1b2c3d4..." // HMAC of mid|web_id|timestamp
}
Success Response — HTTP 200
{
"status": "ok",
"payment": {
"web_id": "ORDER-20250315-001",
"flow_id": "a3f1c8d2e4b09fa72c1d...",
"amount": 1999.99,
"currency": "PKR",
"status": "completed",
"status_code": 200,
"status_description": "The payment was successfully completed and funds received.",
"create_time": "2026-04-03 08:50:42",
"update_time": "2026-04-03 08:51:06",
"payer_email": "buyer@example.com",
"payment_message": "Transaction processed successfully.",
"settlement_status": "unsettled",
"issuer": "JazzCash" // or "EasyPaisa", "OneQR"
}
}
Batch Lookup — Up to 50 IDs at Once
{
"merchant_mid": "MID-ABC123XYZ",
"flow_id": "a3f1c8d2...,b4e2d9f1...,c5f3e0a2...", // comma-separated
"timestamp": 1739683400,
"signature": "..." // signed over IDs sorted alphabetically, comma-joined
}
// Response: { "status":"ok", "count":3, "payments":[{...},{...},{...}] }
For batch requests, sort the IDs alphabetically and join with commas (no spaces) before computing the signature: sort(["c5f3","a3f1","b4e2"]) → "a3f1,b4e2,c5f3".
Batch request میں IDs کو alphabetical ترتیب سے sort کر کے comma سے جوڑیں — پھر اس string سے HMAC بنائیں۔ IDs کے درمیان space نہ ہو۔
Merchant IPN (Webhook)
مرچنٹ IPN — محفوظ نوٹیفکیشن
Checktion sends server-to-server IPNs to your merchant IPN URL when a payment status changes. IPNs are delivered in a uniform JSON structure (not raw provider payloads) and are protected using an HMAC-SHA256 signature in the JSON body.
Checktion آپ کے IPN URL پر server-to-server IPN بھیجتا ہے۔ یہ raw provider data نہیں ہوتا بلکہ uniform JSON ہوتا ہے، اور JSON body میں HMAC-SHA256 signature کے ساتھ secure ہوتا ہے۔
IPNs are sent when Checktion receives a provider update (JazzCash/EasyPaisa IPN) or when the cron job detects a late final status (completed/expired) that was not delivered to your server.
Callback URL
Set your IPN endpoint in your merchant profile (admin panel). Checktion will POST JSON to this URL.
Uniform IPN JSON Payload
{
"merchant_mid": "MID-ABC123XYZ",
"event_id": "12345",
"timestamp": 1739683200,
"signature": "2d4b...",
"flow_id": "a3f1c8d2e4b09fa72c1d8e3f5b607a91",
"status": "completed",
"amount": "1999.99",
"currency": "PKR",
"web_id": "ORDER-20250315-001",
"issuer": "1",
"provider": "jazzcash",
"reference": "T2026040308505404371d",
"message": "Payment completed successfully",
"event_time": "2026-04-03 08:51:06",
"source": "provider_ipn_jazzcash"
}
Expected IPN ACK (Your Response)
Your endpoint must return a JSON acknowledgment containing the same flow_id and a status of completed, expired, or processing.
{
"flow_id": "a3f1c8d2e4b09fa72c1d8e3f5b607a91",
"status": "completed"
}
Signature Verification Logic
sign_string = merchant_mid + "|" + flow_id + "|" + status + "|" +
amount + "|" + currency + "|" + web_id + "|" + timestamp
expected = HMAC_SHA256(sign_string, merchant_api_key)
signature = expected
If you ACK with completed or expired, Checktion stops retries for that payment status. If you ACK with processing or do not ACK properly, Checktion retries (up to 3 total attempts).
اگر آپ completed یا expired ACK دیں تو retries بند ہو جاتی ہیں۔ processing یا غلط/نہ آنے والی ACK پر Checktion دوبارہ کوشش کرتا ہے (زیادہ سے زیادہ 3 بار)۔
Error Reference
خامیوں کا حوالہ
All API errors return a consistent JSON structure. On charge endpoints, errors include a success: false field. On other endpoints, the error is in the error key.
{
"success": false, // only on charge endpoints
"error": "Human-readable error message"
}
| HTTP | Meaning | Action |
|---|---|---|
| 200 | OK — Charge completed / inquiry success | Proceed |
| 201 | Created — Payment record created (/auth/) | Proceed to charge |
| 202 | Accepted — Charge initiated (processing) | Poll /inquire/v1/ |
| 400 | Bad Request — Validation or gateway failure | Fix input or create new payment |
| 401 | Unauthorized — Invalid merchant_mid or signature | Check credentials and signature formula |
| 403 | Forbidden — Inactive merchant or domain mismatch | Contact support |
| 404 | Not Found — flow_id not found or wrong merchant | Check flow_id or create new |
| 405 | Method Not Allowed — Use POST | Use POST method |
| 409 | Conflict — Duplicate web_id | Use a unique web_id |
| 410 | Gone — Payment expired before charge | Create new payment via /auth/ |
| 500 | Server Error — Merchant secret not configured | Contact support |
| 503 | Unavailable — Database connection failure | Retry after short delay |
Quick Reference
تیز رہنما
| Task | Endpoint | Method | Key Response |
|---|---|---|---|
| Create payment for any gateway | /auth/ | POST | flow_id in HTTP 201 |
| Hosted checkout (redirect) | /pay/<flow_id> | GET | Use IPN or /inquire/v1/ to confirm |
| Charge JazzCash wallet | /auth/jazzcash-charge/ | POST | 200=done, 202=poll, 400=fail |
| Charge EasyPaisa wallet | /auth/easypaisa-charge/ | POST | 200=done, 202=poll, 400=fail |
| Generate OneQR code | /auth/oneqr/ | POST | 200=QR generated, poll to confirm |
| Check single payment status | /inquire/v1/ | POST | status + status_code |
| Batch status (up to 50) | /inquire/v1/ | POST | payments[] array with count |
| Receive payment webhooks | Your IPN URL | POST | Verify HMAC, then ACK {flow_id,status} |
Checktion Payment Gateway — Developer Reference v1.2 — 2026
Base URL: https://checktion.com/ · PKR Only · HMAC-SHA256
چیکشن پیمنٹ گیٹ وے — ڈویلپر دستاویز — 2026