Developer docs

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:

bash
https://api.cashierwpay.online

Every 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.

bash
X-Authorization: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx
X-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.

POST/api/v1/payment/create-payment
FieldTypeRequiredDescription
amountstringrequiredDecimal amount, e.g. "1100" or "1100.50".
referencestringrequiredYour unique order ID. Must be unique per merchant — reused values return 409.
callback_urlstringrequiredWhere the customer's browser is redirected after the payment attempt.
webhook_urlstringoptionalServer-to-server URL that receives the final status. See Webhooks below.
cust_namestringrequiredCustomer's name.
cust_phonestringoptionalCustomer's phone number.

Example request

bash
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

json
{
"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

Enter your public and secret key above to send a live request.

Track payment status#

Poll this endpoint to check a payment's current status using your own reference.

GET/api/v1/payment/track-status/:reference
bash
curl "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)"
json
{
"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.

json
{
"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:

json
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#

StatusMeaning
pendingAwaiting the customer to submit payment details, or awaiting admin confirmation.
completedConfirmed — the ledger has been credited to your account.
rejectedCould 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.

POST/api/v1/withdrawal/create-withdrawal
FieldTypeRequiredDescription
amountstringrequiredDecimal 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).
referencestringrequiredYour unique withdrawal ID. Must be unique per merchant — reused values return 409.
currencystringrequiredAlways "BDT".
payout_methodstringrequired"bkash" | "nagad" | "rocket" | "upay" — where the payout is sent.
payout_msisdnstringrequiredDestination wallet number, e.g. "01700000000".
webhook_urlstringoptionalServer-to-server URL that receives the final status. See Withdrawal webhooks below.

Example request

bash
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

json
{
"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.

Enter your public and secret key above to send a live request.

Track withdrawal status#

Poll this endpoint to check a withdrawal's current status using your own reference.

GET/api/v1/withdrawal/track-status/:reference
bash
curl "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)"
json
{
"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.

json
{
"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#

StatusMeaning
pendingSubmitted — queued for payout or awaiting admin action. Funds are held from your balance.
completedPaid out — confirmed sent to payout_msisdn.
rejectedNot paid out. The held amount was released back to your available balance. See reject_msg for the reason, if provided.