DevelopersAPI referenceSupport

Reference

API reference

Three calls and one postback. Base URL https://api.antpay.network. JSON in, JSON out.

CallWhat it does
POST /api/v1/checkoutsCreate a hosted checkout
GET /api/v1/checkouts/{checkoutId}Read a checkout by id
GET /api/v1/transactions/{reference}Read a payment by your reference
POST to your postback URLThe payment result, sent by AntPay to you

Prefer a machine-readable file? Download the OpenAPI description and import it into your API client.

Create a hosted checkout

POSThttps://api.antpay.network/api/v1/checkouts

Creates a hosted payment link for one order. Call it from your server only: your API key must never reach a browser or an app. Then send the customer to checkoutUrl. The AntPay page collects the payer's details, makes the QR and shows the result.

  • Returns 200 with checkoutUrl, checkoutId and expiresAt. The link is https://pay.antpay.network/qr/<checkoutId>.
  • expiresAt is when the link stops accepting customer details. It is not the payment deadline.
  • This response does not include transactionId. You get it in the postback, or as txnId from GET /api/v1/checkouts/{checkoutId}.
  • When a call fails with 4xx, no payment is created. The only exception is a duplicate reference, which already exists. On a 500 or no answer, check GET /api/v1/transactions/{reference} before you retry.
  • The IP allow-list applies to every call, and request signing if it is switched on for your account.
  • Optional accountNumber + walletName: send both and the page opens straight on the QR code; leave both out and it opens on the form.
  • Whole rupees only: 1500, not 1500.50. A decimal amount returns 400 DECIMAL_VALUES_NOT_SUPPORTED.

Headers

HeaderValue
X-Api-Key requiredYour payment key.
Content-Type requiredapplication/json
X-Timestamp, X-SignatureOnly when request signing is on for your account. See Request signing.

Request body

FieldTypeDescription
reference requiredstring

Your order id: 1 to 120 characters from letters, digits, ., _ and -, with no ... Unique per API key; a repeat returns 400. (Other characters are accepted on create, but such a reference cannot be read back with GET /api/v1/transactions/{reference}.)

amount requirednumber

Amount in PKR, whole rupees only, minimum PKR 300 (below that: 400 AMOUNT_NOT_SUPPORTED): 1500, not 1500.50 (1500.00 is fine). A decimal amount returns 400 DECIMAL_VALUES_NOT_SUPPORTED.

paymentMethod required"qr"

"qr" (any case). Always send it.

paymentType required"onetime"

Always "onetime".

returnUrl requiredstring (uri)

Where the page sends the customer after a final result. Use https. We add no query parameters, so your landing page must check the status itself.

successUrlstring (uri)

Optional. Used as the postback URL only when no postback URL is set on your API key or your account.

expiresInnumber

Minutes the customer has to submit their details. Default 15. Values outside 1 to 1380 (23 h) are clamped to that range, not rejected. A missing value, a non-number or 0 becomes 15.

userobject

Free-form metadata. It is returned to you in the webhook field user.

accountNumberstring or null

Optional — send together with walletName. The customer's mobile wallet number: 03XXXXXXXXX or +923XXXXXXXXX (spaces and dashes are ignored). With both fields, the page opens straight on the QR and shows the number masked (e.g. 0312•••4567). null or "" counts as not sent. The webhook's mobile is the number actually paid from, which can differ.

walletName"easypaisa" "jazzcash" "sadapay" "nayapay" or null

Optional — send together with accountNumber. The wallet the number belongs to. Any letter case. null or "" counts as not sent.

Request examples

With accountNumber + walletName — the page opens straight on the QR

{
  "reference": "ORD-10021",
  "amount": 1500,
  "paymentMethod": "qr",
  "paymentType": "onetime",
  "returnUrl": "https://shop.example.com/orders/ORD-10021",
  "expiresIn": 15,
  "user": {
    "customerId": "C-778"
  },
  "accountNumber": "03121234567",
  "walletName": "easypaisa"
}

Without them — the customer picks the wallet and enters the details

{
  "reference": "ORD-10021",
  "amount": 1500,
  "paymentMethod": "qr",
  "paymentType": "onetime",
  "returnUrl": "https://shop.example.com/orders/ORD-10021",
  "expiresIn": 15,
  "user": {
    "customerId": "C-778"
  }
}

Response fields (200)

FieldTypeDescription
successboolean

checkoutUrlstring (uri)

Send the customer here, exactly as returned: https://pay.antpay.network/qr/<checkoutId>. It is also the customer's permanent status page.

checkoutIdstring (uuid)

Store it. It identifies the webhook (checkoutId, id, tokenId) and rebuilds the link.

expiresAtstring (date-time)

When the link stops accepting customer details (now + expiresIn). Not the payment deadline.

Responses

200

Created — send the customer to checkoutUrl. The payment is pending.

{
  "success": true,
  "checkoutUrl": "https://pay.antpay.network/qr/3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
  "checkoutId": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
  "expiresAt": "2026-11-01T10:15:00.000Z"
}

400

Validation failed (errors), or the reference was used before for this API key (error). A duplicate carries no link: get the checkoutId from GET /transactions/{reference} and rebuild the link. A qr amount that is not whole rupees returns the single DECIMAL_VALUES_NOT_SUPPORTED body instead.

Amount below the QR minimum (PKR 300)

{
  "success": false,
  "statusCode": "AMOUNT_NOT_SUPPORTED",
  "error": "Amount not supported. Minimum is PKR 300."
}

validation

{
  "success": false,
  "errors": [
    "paymentType only supports \"onetime\"",
    "returnUrl must be a valid URL"
  ]
}

Amount not whole rupees (e.g. 1500.50)

{
  "success": false,
  "statusCode": "DECIMAL_VALUES_NOT_SUPPORTED",
  "error": "decimal-values-are-not-supported"
}

Only one of accountNumber / walletName sent

{
  "success": false,
  "errors": [
    "accountNumber and walletName must be passed together"
  ]
}

walletName not allowed

{
  "success": false,
  "errors": [
    "walletName must be one of easypaisa, jazzcash, sadapay, nayapay"
  ]
}

accountNumber not a mobile wallet number

{
  "success": false,
  "errors": [
    "accountNumber must be a mobile wallet number, e.g. 03001234567"
  ]
}

missing

{
  "success": false,
  "errors": [
    "reference is required",
    "amount is required",
    "paymentType is required",
    "returnUrl is required"
  ]
}

duplicate

{
  "success": false,
  "error": "Duplicate reference. Transaction with this reference already exists for this API key."
}

401

Missing or invalid API key, or a key not attached to a merchant. When request signing is on for your account, a signing error also returns 401. Nothing created.

missing

{
  "success": false,
  "error": "Missing X-Api-Key header"
}

invalid

{
  "success": false,
  "error": "Invalid API key"
}

noMerchant

{
  "success": false,
  "error": "API key has no merchant association"
}

Request signing is on and the signature failed

{
  "success": false,
  "error": {
    "code": "SIGNATURE_INVALID",
    "message": "Request signature rejected (bad_signature)."
  }
}

403

Your account is not active, or the calling IP is not on your allow-list. Nothing created.

inactive

{
  "success": false,
  "error": "MERCHANT_INACTIVE",
  "message": "This merchant account is not active. Contact support."
}

noAllowlist

{
  "success": false,
  "error": "IP_ALLOWLIST_NOT_CONFIGURED",
  "message": "This merchant has no IP allowlist configured on production. Contact your account manager to add your server IPs."
}

ipNotAllowed

{
  "success": false,
  "error": "IP_NOT_ALLOWED",
  "message": "Your IP is not on this merchant's allowlist. Contact your account manager to add it."
}

422

Your account is not set up for QR yet. Nothing created — contact your account manager; your request is fine.

noRate

{
  "success": false,
  "status": "failed",
  "statusCode": "NO_RATE_CONFIGURED",
  "message": "QR is not fully configured for this merchant"
}

notEnabled

{
  "success": false,
  "status": "failed",
  "statusCode": "NO_PSP_ROUTE",
  "error": "No QR payment processor configured for this merchant"
}

429

Rate limit exceeded. Back off for Retry-After seconds.

{
  "success": false,
  "error": "Too Many Requests",
  "message": "Rate limit exceeded: 300 requests per minute",
  "retryAfter": 12
}

500

The checkout may or may not exist. Check GET /transactions/{reference} before you retry.

{
  "success": false,
  "error": "Failed to create checkout session"
}

Get a checkout

GEThttps://api.antpay.network/api/v1/checkouts/{checkoutId}

Returns one of your checkouts by checkoutId, including our txnId (the transactionId in postbacks). A checkout of another merchant is simply not found. IP allow-listed.

If you sent accountNumber + walletName when you created it, both come back here (the number masked, e.g. 0312•••4567); otherwise both are null.

Treat the postback as the primary signal; poll as a fallback only, no more often than every 10 s per payment.

Headers

HeaderValue
X-Api-Key requiredYour payment key.
X-Timestamp, X-SignatureOnly when request signing is on for your account. See Request signing.

Path

ParameterTypeDescription
checkoutId requiredstring (uuid), in the path

The checkoutId from POST /checkouts.

Response fields (200)

FieldTypeDescription
successboolean

checkoutobject

checkout object

FieldTypeDescription
checkoutIdstring (uuid)

txnIdstring or null

Our transactionId, e.g. FDX-1A2B3C4D.

referencestring

amountnumber

PKR. On QR payments, the payable amount once a QR exists.

paymentMethodstring

status"pending" "completed" "failed"

createdAtstring (date-time)

walletName"easypaisa" "jazzcash" "sadapay" "nayapay" or null

The walletName you sent on POST /checkouts; null when you did not send it.

accountNumberstring or null

The accountNumber you sent, masked (e.g. 0312•••4567); null when you did not send it. The full number is never returned.

Responses

200

The checkout.

{
  "success": true,
  "checkout": {
    "checkoutId": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
    "txnId": "FDX-1A2B3C4D",
    "reference": "ORD-10021",
    "amount": 1500,
    "paymentMethod": "qr",
    "status": "pending",
    "createdAt": "2026-11-01T10:00:00.000Z",
    "walletName": "easypaisa",
    "accountNumber": "0312•••4567"
  }
}

401

Missing or invalid API key, or a key not attached to a merchant (or a signing error when signing is on).

Key problem

{
  "success": false,
  "error": "API key has no merchant association"
}

Request signing is on and the signature failed

{
  "success": false,
  "error": {
    "code": "SIGNATURE_INVALID",
    "message": "Request signature rejected (bad_signature)."
  }
}

403

The calling IP is not on your allow-list.

{
  "success": false,
  "error": "IP_NOT_ALLOWED",
  "message": "Your IP is not on this merchant's allowlist. Contact your account manager to add it."
}

404

No checkout with that id for your merchant. This is the API's own answer. A 404 whose body is {"success":false,"error":"NOT_FOUND"} means the address was refused before it reached the API (a wrong path, or a reference or id with characters that cannot travel in a URL): it says nothing about whether the payment exists.

{
  "success": false,
  "error": "Checkout session not found"
}

429

Rate limit exceeded. Back off for Retry-After seconds.

500

Internal error — retry later.

{
  "success": false,
  "error": "Failed to retrieve checkout session"
}

Get a payment by your reference

GEThttps://api.antpay.network/api/v1/transactions/{reference}

Returns the payment for one of your references, with its checkoutId and our txnId. Use it after an unclear create (timeout or 5xx), or to rebuild a hosted link as https://pay.antpay.network/qr/<checkoutId>. The lookup is per merchant: if you use more than one API key, keep references unique across all of them. IP allow-listed.

statusCode is null while the payment is pending.

Headers

HeaderValue
X-Api-Key requiredYour payment key.
X-Timestamp, X-SignatureOnly when request signing is on for your account. See Request signing.

Path

ParameterTypeDescription
reference requiredstring, in the path

Your order reference (URL-encode it).

Response fields (200)

FieldTypeDescription
successboolean

transactionobject

transaction object

FieldTypeDescription
referencestring

txnIdstring or null

Our transactionId.

checkoutIdstring (uuid)

Rebuild a hosted link as https://pay.antpay.network/qr/<checkoutId>.

amountnumber

PKR. On QR payments, the payable amount once a QR exists.

paymentMethodstring

status"pending" "completed" "failed"

statusCodestring or null

null while the payment is pending.

createdAtstring (date-time)

updatedAtstring (date-time)

walletName"easypaisa" "jazzcash" "sadapay" "nayapay" or null

The walletName you sent on POST /checkouts; null when you did not send it.

accountNumberstring or null

The accountNumber you sent, masked (e.g. 0312•••4567); null when you did not send it. The full number is never returned.

Responses

200

The payment.

{
  "success": true,
  "transaction": {
    "reference": "ORD-10021",
    "txnId": "FDX-1A2B3C4D",
    "checkoutId": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
    "amount": 1500,
    "paymentMethod": "qr",
    "status": "completed",
    "statusCode": "SUCCESS",
    "createdAt": "2026-11-01T10:00:00.000Z",
    "updatedAt": "2026-11-01T10:04:12.000Z",
    "walletName": "easypaisa",
    "accountNumber": "0312•••4567"
  }
}

401

Missing or invalid API key, or a key not attached to a merchant (or a signing error when signing is on).

Key problem

{
  "success": false,
  "error": "API key has no merchant association"
}

Request signing is on and the signature failed

{
  "success": false,
  "error": {
    "code": "SIGNATURE_INVALID",
    "message": "Request signature rejected (bad_signature)."
  }
}

403

The calling IP is not on your allow-list.

{
  "success": false,
  "error": "IP_NOT_ALLOWED",
  "message": "Your IP is not on this merchant's allowlist. Contact your account manager to add it."
}

404

No payment with that reference for your merchant. This is the API's own answer. A 404 whose body is {"success":false,"error":"NOT_FOUND"} means the address was refused before it reached the API (a wrong path, or a reference or id with characters that cannot travel in a URL): it says nothing about whether the payment exists.

{
  "success": false,
  "error": "Transaction not found"
}

429

Rate limit exceeded. Back off for Retry-After seconds.

500

Internal error — retry later.

{
  "success": false,
  "error": "Failed to retrieve transaction status"
}

Payment result postback

POSTyour postback URL

Sent to your postback URL once, when the payment reaches its final state (completed or failed). You never receive one for pending.

Header X-Mint-Signature: sha256=<hex> is the HMAC-SHA256 of the raw request body with your postback secret. Verify it against the raw bytes you receive, before you parse them.

Any 2xx within 10 s acknowledges it. Otherwise we try again: 3 attempts in total, 5 s apart. A postback can arrive more than once, so record it once per transactionId + status.

  • amount is the amount paid; requestedAmount is your order amount.
  • qr is absent if no QR was ever created. qr.imageUrl is null.
  • mobile / customerMobile is the number the customer entered on the page.
  • statusCode EXPIRED (status: "failed"): no payment within the window, or the link expired before the customer submitted details.
  • A failed payment normally stays failed; nothing changes it by itself. If the payment network confirms that it was paid, AntPay staff correct it to completed and you then get a second postback (status: completed, statusCode: SUCCESS, pspStatusCode: MANUAL_SUCCESS). This is not automatic and can take hours or days. A later completed replaces an earlier failed.

Headers we send

HeaderValue
Content-Typeapplication/json
X-Mint-Signaturesha256= + hex HMAC-SHA256 of the raw body with your postback secret. See Verify the signature.

Body

FieldTypeDescription
successboolean

API-call success only — NOT the payment outcome. Branch on status.

referencestring

transactionIdstring or null

Merchant-facing id, e.g. FDX-A1B2C3D4.

paymentMethodstring

mobilestring or null

amountnumber

The amount in PKR: what was paid, and what settles. Reconcile on this.

requestedAmountnumber

Your order amount.

status"pending" "completed" "failed"

statusCode"PENDING" "SUCCESS" "FAILED" "TIMEOUT" "INSUFFICIENT_FUNDS" "ACCOUNT_DEACTIVATED" …

pspStatusCodestring or null

Raw processor code. For analytics only: do not branch on it.

pspOrderIdstring or null

The id we sent to the payment processor.

pspTxnIdstring or null

The id the payment processor returned.

messagestring

failureReasonstring or null

Non-null only when status is failed.

attemptCountinteger

Present on the postback.

attemptsarray of objects

Present on the postback.

qrobject

payload, imageUrl, expiresAt, payableAmount. Absent when no QR was ever created.

createdAtstring (date-time)

updatedAtstring (date-time)

idstring

The checkoutId.

vendorIdstring

Identifies your API key.

checkoutIdstring

The checkoutId from POST /api/v1/checkouts.

acknowledgedboolean

Always false.

tokenIdstring

The checkoutId.

customerMobilestring

The number the customer entered on the page (same value as mobile). Absent when unknown.

userobject

The user object from your checkout. Can be {}.

attempts[ ] object

FieldTypeDescription
attemptNumberinteger

pspOrderIdstring or null

pspTxnIdstring or null

pspStoreIdstring or null

pspStatusCodestring or null

messagestring

outcome"success" "failure" "timeout" "transport_error" "pending"

startedAtstring (date-time)

completedAtstring or null (date-time)

durationMsinteger or null

qr object

FieldTypeDescription
payloadstring or null

Raw EMVCo QR text. Render it with any QR library exactly as received — never trim, re-encode, URL-encode or alter it; the string ends with a checksum and any change makes the code unscannable.

imageUrlstring or null (uri)

null on hosted checkout: the AntPay page draws the QR itself.

expiresAtstring or null (date-time)

ISO-8601, UTC. After this instant the QR cannot be paid. An unpaid payment is reported failed / EXPIRED later than this, never earlier than 30 minutes after the QR was created.

payableAmountstring or null

The exact amount the customer must pay, as a 2-decimal string ("1500.00"). Show "Pay exactly Rs 1500.00". It equals your order amount; see *Amounts on QR payments* on the transaction envelope.

Examples

Paid (completed / SUCCESS)

{
  "success": true,
  "reference": "ORD-10021",
  "transactionId": "FDX-1A2B3C4D",
  "paymentMethod": "qr",
  "mobile": "03001234567",
  "amount": 1500,
  "status": "completed",
  "statusCode": "SUCCESS",
  "pspStatusCode": "SUCCESS",
  "pspOrderId": "FDX-1A2B3C4D",
  "pspTxnId": "01JABCDEF0000000000000000",
  "message": "Payment completed successfully",
  "failureReason": null,
  "createdAt": "2026-11-01T10:00:00.000Z",
  "updatedAt": "2026-11-01T10:04:12.000Z",
  "attemptCount": 1,
  "attempts": [
    {
      "attemptNumber": 1,
      "pspOrderId": "FDX-1A2B3C4D",
      "pspTxnId": "01JABCDEF0000000000000000",
      "pspStoreId": null,
      "pspStatusCode": "pending",
      "message": "QR created",
      "outcome": "success",
      "startedAt": "2026-11-01T10:01:02.000Z",
      "completedAt": "2026-11-01T10:01:03.000Z",
      "durationMs": 850
    }
  ],
  "requestedAmount": 1500,
  "qr": {
    "payload": "000201010212…6304ABCD",
    "imageUrl": null,
    "expiresAt": "2026-11-01T10:16:02.000Z",
    "payableAmount": "1500.00"
  },
  "id": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
  "vendorId": "MERCHANT_000123_PK1",
  "checkoutId": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
  "acknowledged": false,
  "tokenId": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
  "customerMobile": "03001234567",
  "user": {
    "customerId": "C-778"
  }
}

Not paid in time (failed / EXPIRED)

{
  "success": true,
  "reference": "ORD-10021",
  "transactionId": "FDX-1A2B3C4D",
  "paymentMethod": "qr",
  "mobile": "03001234567",
  "amount": 1500,
  "status": "failed",
  "statusCode": "EXPIRED",
  "pspStatusCode": "EXPIRED",
  "pspOrderId": "FDX-1A2B3C4D",
  "pspTxnId": "01JABCDEF0000000000000000",
  "message": "QR code expired before it was paid",
  "failureReason": "QR code expired before it was paid",
  "createdAt": "2026-11-01T10:00:00.000Z",
  "updatedAt": "2026-11-01T10:17:10.000Z",
  "attemptCount": 1,
  "attempts": [
    {
      "attemptNumber": 1,
      "pspOrderId": "FDX-1A2B3C4D",
      "pspTxnId": "01JABCDEF0000000000000000",
      "pspStoreId": null,
      "pspStatusCode": "pending",
      "message": "QR created",
      "outcome": "failure",
      "startedAt": "2026-11-01T10:01:02.000Z",
      "completedAt": "2026-11-01T10:01:03.000Z",
      "durationMs": 850
    }
  ],
  "requestedAmount": 1500,
  "qr": {
    "payload": "000201010212…6304ABCD",
    "imageUrl": null,
    "expiresAt": "2026-11-01T10:16:02.000Z",
    "payableAmount": "1500.00"
  },
  "id": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
  "vendorId": "MERCHANT_000123_PK1",
  "checkoutId": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
  "acknowledged": false,
  "tokenId": "3f6c1d2e-8a4b-4c1e-9d7a-2b5e6f7a8c90",
  "customerMobile": "03001234567",
  "user": {
    "customerId": "C-778"
  }
}

Your answer

Return any 2xx within 10 s to acknowledge. Otherwise we try again: 3 attempts in total, 5 s apart.