Home / Developers
Merchant Integration Docs

Payin and payout APIs, integrated in a few steps

A unified HTTP + JSON interface with SHA-256 signature verification, async notifications, and on-demand order queries. This page covers signing rules, every API field, and request examples.

Overview

India Payme offers merchants two core transaction capabilities: Payin — collecting payments from end users on the merchant's behalf; and Payout — sending payments to a specified account on the merchant's behalf. Every API is a POST with a JSON body and must include an API signature. Once processing completes, the platform calls back the merchant with an async notification, and on-demand order queries are also supported.

CapabilityMethodPath
Payin OrderPOST/transaction/payin/v1/apply
Payin QueryPOST/transaction/payin/v1/query
Payout OrderPOST/transaction/payout/v1/apply
Payout QueryPOST/transaction/payout/v1/query
Balance QueryPOST/transaction/payout/v1/balance

Base URL (use the production gateway domain provided by the platform after you open an account):

https://{gateway-domain}

Integration Prerequisites

Log in to the merchant dashboard → App Keys. Each app has a pair of credentials: appKey and appSecret. The appKey is used as the appId request header; appSecret is your signing key, used only for local signature calculation — never transmitted.

Every request must include the following HTTP headers, with Content-Type set to application/json:

HeaderRequiredDescription
appIdYesMerchant app ID (i.e. your appKey)
timestampYesUnix timestamp in milliseconds
nonceYesRandom string, ≥10 characters, single-use only
signYesSignature computed per the rules below

Signing Rules

The signing algorithm is plain SHA-256 (lowercase hex) — not HMAC. The appSecret is appended directly to the end of the string to be signed before hashing. Steps:

  1. Combine the top-level request body fields (non-empty only) with the signature headers appId, timestamp, and nonce into a single map (sign itself is excluded);
  2. Sort keys in ascending ASCII order and join them as key1=value1&key2=value2…;
  3. Append appSecret directly to the end (no separator), then take the SHA-256 hash of the full string in lowercase hex to get sign.
# string to sign signString = "key1=value1&key2=value2…&keyN=valueN" + appSecret sign = SHA256_HEX(signString) // lowercase hex

Expiry and replay protection:

  • Timestamp validity window is 30 seconds: |server time − timestamp| ≤ 30s. Requests outside this window return timestamp has expired. Make sure your client and the gateway have synchronized clocks (NTP).
  • Nonce replay protection: each nonce can be used only once — reuse returns nonce has been used (error code 900).
  • Empty fields are excluded from the signature — the set of fields included in the signature must exactly match the fields actually sent in the JSON body.

Node.js signing example:

const crypto = require('crypto'); function buildSign(appId, appSecret, timestamp, nonce, body) { const params = { ...body, appId, timestamp, nonce }; const signString = Object.keys(params) .filter(k => params[k] !== null && params[k] !== undefined) .sort() .map(k => `${k}=${params[k]}`) .join('&') + appSecret; return crypto.createHash('sha256').update(signString, 'utf8').digest('hex'); }

Payin Order POST

POST /transaction/payin/v1/apply — creates a payment collection order and returns a checkout link payUrl that guides the user to complete payment.

FieldTypeRequiredDescription
merchantOrderNostringYesMerchant order number, must be unique
amountnumberYesOrder amount, decimal (e.g. 100.02)
namestringYesCustomer name. English letters only, ≥3 characters, spaces allowed, no symbols or digits
phonestringYesPhone number
emailstringYesEmail address
currencystringYesCurrency: INR / PKR / USDT / BDT
productstringYesPayment product code, issued by the platform per your agreement
notifyUrlstringNoAsync notification URL; falls back to your default notification address if omitted
returnUrlstringNoRedirect page shown after successful payment
payTypestringNoDirect wallet payment method: JAZZCASH / EASYPAISA / BKASH / NAGAD
POST /transaction/payin/v1/apply { "merchantOrderNo": "ORD1751731200123", "amount": "600.00", "currency": "INR", "product": "{product-code}", "name": "John Doe", "phone": "9910099100", "email": "john@example.com", "notifyUrl": "https://shop.example/pay/notify" }
// response { "code": 0, "msg": "Success", "data": { "orderNo": "P1751731200999", "merchantOrderNo": "ORD1751731200123", "amount": 600, "currency": "INR", "payUrl": "https://{checkout-domain}/cashier/xxxx", "payStatus": 0 } }

Once you have payUrl, redirect the user to complete payment. The final result is confirmed via the async notification.

Payout Order POST

POST /transaction/payout/v1/apply — initiates a payment to a specified account. Processed asynchronously: the API first validates and holds the account, then matches a channel to disburse funds asynchronously. The immediate response is typically payStatus=0 (accepted), with the final outcome confirmed via query or notification.

FieldTypeRequiredDescription
merchantOrderNostringYesMerchant order number
amountnumberYesPayment amount, minimum 100.00
accountNamestringYesRecipient name. English letters only, ≥3 characters, spaces allowed
accountstringYesRecipient account number
phonestringYesPhone number
emailstringYesEmail address
currencystringYesCurrency: INR / PKR / USDT / BDT
bizCodestringYesDisbursement type: IMPS / UPI / BANK / JAZZCASH / EASYPAISA / BKASH / NAGAD / ECARD
payCodestringYesPayment method: CARD / WALLET / NBK / ITT / VC
branchCodestringYesClearing code: IFSC for India; bank code for Pakistan; per bizCode for Bangladesh
productstringYesPayout product code, issued by the platform
bankNamestringNoBank name
swiftCodestringNoSWIFT code (used for cross-border wire transfers via ITT)
POST /transaction/payout/v1/apply { "merchantOrderNo": "PO1751731200123", "amount": "1500.00", "currency": "INR", "product": "{product-code}", "accountName": "John Doe", "account": "1234567890", "bizCode": "IMPS", "payCode": "NBK", "branchCode": "HDFC0000001", "bankName": "HDFC", "phone": "9910099100", "email": "john@example.com" }

Order Query POST

Payin: POST /transaction/payin/v1/query. Payout: POST /transaction/payout/v1/query. Pass merchantOrderNo or orderNo to locate the order. Rate limit: 5 requests/second.

POST /transaction/payin/v1/query { "merchantOrderNo": "ORD1751731200123" }
// response data { "orderNo": "P1751731200999", "merchantOrderNo": "ORD1751731200123", "amount": 600, "realAmount": 600, "currency": "INR", "payStatus": 1 // 0 processing / 1 paid / -1 cancelled }

Balance Query POST

POST /transaction/payout/v1/balance — queries the merchant account balance. Rate limit: 5 requests/second.

POST /transaction/payout/v1/balance { "currency": "INR" }
// response data { "accountNo": "ACC0001", "currency": "INR", "balance": 100000.00, // total balance "balanceActive": 98500.00, // available balance "balanceFreeze": 1500.00 // frozen balance }

Async Notifications

Once an order reaches a final state, the platform sends a POST (JSON) notification to the merchant's notifyUrl (or the default address if none was provided), including the same signature headers (appId/timestamp/nonce/sign). Merchants should recompute the signature with their own appSecret using the same rules and compare it to verify the notification is authentic.

The payin notification payload includes: merchantOrderNo, orderNo, currency, product, amount, realAmount, and status ("1" for a successful payment). The payout notification additionally includes utr (bank reference number) and statusDes (status description), where status is "1" for success or "2" for failure.

// example payin notification body { "merchantOrderNo": "ORD1751731200123", "orderNo": "P1751731200999", "currency": "INR", "product": "{product-code}", "amount": "600.00", "realAmount": "600.00", "status": "1" }

Merchants must respond with the plain text OK or success (case-insensitive). Otherwise the platform queues a retry: up to 5 attempts, with increasing intervals in minutes (1 / 2 / 5 / 10 / 30 / 60 / 120). Your notification handler must therefore be idempotent — the same orderNo may be delivered more than once.

Order Status

Integrate against the following public-facing statuses (the internal state machine is more granular and not exposed directly):

ScenarioFieldValues
Order creation responsepayStatus0 created / 1 success / 2 failed / 3 cancelled
Payin querypayStatus0 processing / 1 paid / -1 cancelled
Payout querypayStatus0 pending / 1 paid / -1 cancelled
Async notificationstatusPayin success "1"; payout "1" success / "2" failed

Error Codes

A response with code != 0 indicates failure, with msg giving the reason. Common business error codes:

codeDescription
0Success
400Invalid parameter / signature verification failed (Sign invalid)
900Duplicate request / nonce replay
10000 / 10001App not found / app disabled
10002Currency not supported
10003 / 10007Merchant disabled / merchant account disabled
10004Product not enabled or agreement expired
10005 / 10009No channel available / channel temporarily unavailable
10008Insufficient account balance
10010IP not in allowlist
10011 / 10012Invalid product / invalid payment method
10020Duplicate merchant order number
30001 / 30002Invalid order number / invalid currency or account not activated

Full Integration Flow

Using payin as an example:

  1. Assemble the request body (see the "Payin Order" fields above).
  2. Generate a timestamp (milliseconds) and a nonce (random string, ≥10 characters).
  3. Compute sign per the "Signing Rules" above.
  4. Send POST /transaction/payin/v1/apply with the 4 signature headers plus the JSON body.
  5. If code==0, take data.payUrl and redirect the user to complete payment.
  6. Listen for the async notification; you can also query the order on demand to confirm the final status.
  7. On receiving the notification, verify the signature, process the transaction, and respond with the plain text OK.

Note: the API paths, fields, and status codes described here match the production implementation. The production gateway domain, available product codes, and IP allowlist policy will be provided by the platform once your account is set up.

Get your keys and start building

Open an account online to receive test credentials and product codes — go live with one click once your sandbox integration is verified.