API reference
Integrate bKash, Nagad, Rocket, and Upay collection and payout into your own site or app — a hosted checkout for deposits, a simple REST call for payouts, and webhooks for both.
Used only to send the live "Try it" requests below — kept in this browser tab's memory and never stored or sent anywhere else.
Getting started#
All requests are made over HTTPS to your base URL:
https://api.cashierwpay.onlineEvery request to the payment API must include your public and secret key as headers. Never expose your secret key in client-side code — only call these endpoints from your own server.
X-Authorization: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxX-Authorization-Secret: sk_live_•••••••••••••••••••••••• (shown once, at generation)Create a payment#
Creates a payment request and returns a hosted checkout URL to redirect your customer to.
/api/v1/payment/create-payment| Field | Type | Required | Description |
|---|---|---|---|
| amount | string | required | Decimal amount, e.g. "1100" or "1100.50". |
| reference | string | required | Your unique order ID. Must be unique per merchant — reused values return 409. |
| callback_url | string | required | Where the customer's browser is redirected after the payment attempt. |
| webhook_url | string | optional | Server-to-server URL that receives the final status. See Webhooks below. |
| cust_name | string | required | Customer's name. |
| cust_phone | string | optional | Customer's phone number. |
Example request
curl -X POST "https://api.cashierwpay.online/api/v1/payment/create-payment" \ -H "X-Authorization: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \ -H "X-Authorization-Secret: sk_live_•••••••••••••••••••••••• (shown once, at generation)" \ -H "Content-Type: application/json" \ -d '{ "amount": "1100", "reference": "inv_smart_001", "callback_url": "https://example.com/callback", "webhook_url": "https://example.com/webhook", "cust_name": "Jhon Doe" }'Example response
{ "success": true, "message": "Payment request created successfully", "data": { "request_id": "aWJ2X3Rva2VuX2V4YW1wbGU", "amount": "1100", "reference": "inv_smart_001", "currency": "BDT", "issue_time": "2026-07-16 04:15:00", "payment_url": "https://pay.cashierwpay.online/checkout/aWJ2X3Rva2VuX2V4YW1wbGU" }}Duplicate reference returns HTTP 409 with code: "DUPLICATE_REFERENCE". Deposits disabled for your account returns HTTP 422 with code: "DEPOSITS_DISABLED".
Try it
Track payment status#
Poll this endpoint to check a payment's current status using your own reference.
/api/v1/payment/track-status/:referencecurl "https://api.cashierwpay.online/api/v1/payment/track-status/inv_smart_001" \ -H "X-Authorization: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \ -H "X-Authorization-Secret: sk_live_•••••••••••••••••••••••• (shown once, at generation)"{ "success": true, "data": { "request_id": "aWJ2X3Rva2VuX2V4YW1wbGU", "amount": "1100.00", "original_amount": null, "amount_adjusted": false, "payment_method": "bkash", "reference": "inv_smart_001", "cust_name": "Jhon Doe", "cust_phone": null, "note": null, "reject_msg": null, "payment_method_trx": "TX123456", "status": "pending" }}status is one of pending, completed, or rejected.
Adjusted amounts. If the customer pays a different amount than you requested, the deposit is normally held for manual admin review. An admin can turn on amount auto-adjustment for your account individually (it is off by default, opted in per merchant). When it is on, such a deposit is instead completed at the amount actually paid. amount always reflects what was actually paid and credited to you; when that differs from your request, amount_adjusted is true and original_amount holds the amount you originally requested (otherwise they are null and false). Always fulfil against amount.
Try it
Enter your public and secret key above to send a live request.
Webhooks#
If you provided a webhook_url, we send one POST request when the payment reaches a final state (completed or rejected — pending payments never trigger a webhook). A payment that isn't confirmed before its window passes is treated as a failed attempt, so an unpaid link fires a rejected webhook shortly after it times out. We attempt delivery once; if it fails, you can always fall back to Track Payment Status, or an admin can manually resend it from their side.
{ "signature": "6294408b326cf940cad20816cda5aa96c234fcabfeef49d013be6e6daeb9514e", "data": { "request_id": "aWJ2X3Rva2VuX2V4YW1wbGU", "amount": "1100.00", "original_amount": null, "amount_adjusted": false, "payment_method": "bkash", "reference": "inv_smart_001", "cust_name": "Jhon Doe", "cust_phone": null, "note": null, "reject_msg": null, "payment_method_trx": "TX123456", "status": 1, "status_name": "completed" }}amount, original_amount, and amount_adjusted carry the same meaning as in Track payment status above. If an admin has enabled amount auto-adjustment for your account (off by default, opted in per merchant) and the customer paid a different amount than requested, amount is the amount actually paid, original_amount is what you requested, and amount_adjusted is true. The note field carries a human-readable summary of the adjustment.
Verifying the signature
signature is an HMAC-SHA256 hex digest of JSON.stringify(data), keyed with your secret key. Recompute it and compare before trusting the payload:
const crypto = require("crypto"); function verify(payload, secretKey) { const expected = crypto .createHmac("sha256", secretKey) .update(JSON.stringify(payload.data)) .digest("hex"); return expected === payload.signature;}status is a numeric code (1 = completed, 3 = rejected); status_name is the human-readable form. Your endpoint should respond with HTTP 200 promptly — slow or failing endpoints won't be retried automatically in the current version.
Status reference#
| Status | Meaning |
|---|---|
| pending | Awaiting the customer to submit payment details, or awaiting admin confirmation. |
| completed | Confirmed — the ledger has been credited to your account. |
| rejected | Could not be confirmed — a wrong or reused transaction ID, an admin rejection, or the payment window passing without confirmation. See reject_msg for the reason, if provided. |
Create a withdrawal#
Requests a payout from your available balance to an MFS wallet. The full amount is delivered to the destination; any withdrawal fee is charged on top, so amount + fee is held from your available balance immediately — see Withdrawal status reference below for what happens to the hold on each outcome.
/api/v1/withdrawal/create-withdrawal| Field | Type | Required | Description |
|---|---|---|---|
| amount | string | required | Decimal amount to pay out, e.g. "500" or "500.50". Delivered in full to the destination; any configured fee is added on top and debited from your balance (you are charged amount + fee). |
| reference | string | required | Your unique withdrawal ID. Must be unique per merchant — reused values return 409. |
| currency | string | required | Always "BDT". |
| payout_method | string | required | "bkash" | "nagad" | "rocket" | "upay" — where the payout is sent. |
| payout_msisdn | string | required | Destination wallet number, e.g. "01700000000". |
| webhook_url | string | optional | Server-to-server URL that receives the final status. See Withdrawal webhooks below. |
Example request
curl -X POST "https://api.cashierwpay.online/api/v1/withdrawal/create-withdrawal" \ -H "X-Authorization: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \ -H "X-Authorization-Secret: sk_live_•••••••••••••••••••••••• (shown once, at generation)" \ -H "Content-Type: application/json" \ -d '{ "amount": "500", "reference": "wd_smart_001", "currency": "BDT", "payout_method": "bkash", "payout_msisdn": "01700000000", "webhook_url": "https://example.com/webhook" }'Example response
{ "success": true, "message": "Withdrawal request created successfully", "data": { "request_id": "aWJ2X3Rva2VuX2V4YW1wbGU", "amount": "500", "fee": "0.00", "net_amount": "500.00", "total_debit": "500.00", "reference": "wd_smart_001", "currency": "BDT", "payout_method": "bkash", "payout_msisdn": "01700000000", "issue_time": "2026-07-18 04:15:00", "status": "pending" }}net_amount is what the destination receives (equal to amount). total_debit is what leaves your available balance (amount + fee).
Duplicate reference returns HTTP 409 with code: "DUPLICATE_REFERENCE". Withdrawals disabled for your account returns HTTP 422 with code: "WITHDRAWALS_DISABLED".
Try it
This holds the amount from your real available balance immediately (a live WITHDRAWAL_HOLD) — cancel it from the panel's Withdrawals page afterward if you don't want it to actually reach an admin for approval.
Track withdrawal status#
Poll this endpoint to check a withdrawal's current status using your own reference.
/api/v1/withdrawal/track-status/:referencecurl "https://api.cashierwpay.online/api/v1/withdrawal/track-status/wd_smart_001" \ -H "X-Authorization: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \ -H "X-Authorization-Secret: sk_live_•••••••••••••••••••••••• (shown once, at generation)"{ "success": true, "data": { "request_id": "aWJ2X3Rva2VuX2V4YW1wbGU", "amount": "500.00", "fee": "0.00", "net_amount": "500.00", "total_debit": "500.00", "reference": "wd_smart_001", "payout_method": "bkash", "payout_msisdn": "01700000000", "note": null, "reject_msg": null, "payout_method_trx": null, "status": "pending" }}status is one of pending, completed, or rejected.
Try it
Enter your public and secret key above to send a live request.
Withdrawal webhooks#
If you provided a webhook_url when creating the withdrawal, we send one POST request when it reaches a final state (completed or rejected — pending withdrawals never trigger a webhook). Same delivery mechanics as payment webhooks above: one best-effort attempt, no automatic retry.
{ "signature": "6294408b326cf940cad20816cda5aa96c234fcabfeef49d013be6e6daeb9514e", "data": { "request_id": "aWJ2X3Rva2VuX2V4YW1wbGU", "amount": "500.00", "fee": "0.00", "net_amount": "500.00", "total_debit": "500.00", "payout_method": "bkash", "payout_msisdn": "01700000000", "reference": "wd_smart_001", "note": null, "reject_msg": null, "payout_method_trx": "TX123456", "status": 1, "status_name": "completed" }}Verified exactly like a payment webhook — recompute the HMAC-SHA256 hex digest of JSON.stringify(payload.data), keyed with your secret key, and compare it against signature (see the verify() function under Webhooks above — it works unchanged for this payload too).
Withdrawal status reference#
| Status | Meaning |
|---|---|
| pending | Submitted — queued for payout or awaiting admin action. Funds are held from your balance. |
| completed | Paid out — confirmed sent to payout_msisdn. |
| rejected | Not paid out. The held amount was released back to your available balance. See reject_msg for the reason, if provided. |