Send payouts to customer MFS wallets (bKash, Nagad, Rocket, Upay) via the v1 Withdraw API.
Withdraw funds directly to customer mobile wallets via bKash, Nagad, Rocket, and more — instantly and automatically.
The Withdraw API enables merchants to send funds directly to customers' mobile financial service (MFS) accounts. The specified amount is deducted from the merchant's balance and transferred to the customer's wallet automatically.
Use this endpoint to create a cash-in request for a customer. Requires authentication via X-Authorization and X-Authorization-Secret headers. The request will deduct the specified amount from the merchant's balance and initiate a payment to the customer's mobile financial service (MFS) account. The response will include a unique transaction ID (trxid) for tracking the payment status.
curl -X POST "https://bdpay.llc/api/v1/mfs/create" \
-H "X-Authorization: pk_test_123..." \
-H "X-Authorization-Secret: sk_test_456..." \
-H "Content-Type: application/json" \
-d '{
"amount": 20,
"mfs_operator": "bkash",
"cust_number":"0123456789",
"withdraw_id":"012458756",
"webhook_url": "https://example.com/withdraw-callback"
}'
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://bdpay.llc/api/v1/mfs/create",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
"X-Authorization: pk_test_123...",
"X-Authorization-Secret: sk_test_456...",
"Content-Type: application/json"
),
CURLOPT_POSTFIELDS => '{
"amount": 100.00,
"mfs_operator": "bKash",
"cust_number": "+8801712345678",
"withdraw_id":"012458756",
"webhook_url": "https://example.com/withdraw-callback"
}'
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
import requests
url = "https://bdpay.llc/api/v1/mfs/create"
headers = {
"X-Authorization": "pk_test_123...",
"X-Authorization-Secret": "sk_test_456...",
"Content-Type": "application/json"
}
payload = {
"amount": 100.00,
"mfs_operator": "bKash",
"cust_number": "+8801712345678",
"withdraw_id":"012458756",
"webhook_url": "https://example.com/withdraw-callback"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://bdpay.llc/api/v1/mfs/create";
const headers = {
"X-Authorization": "pk_test_123...",
"X-Authorization-Secret": "sk_test_456...",
"Content-Type": "application/json"
};
const payload = {
amount: 100.00,
mfs_operator: "bKash",
cust_number: "+8801712345678",
withdraw_id:"012458756",
webhook_url: "https://example.com/withdraw-callback"
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var url = "https://bdpay.llc/api/v1/mfs/create";
var payload = new
{
amount = 100.00,
mfs_operator = "bKash",
cust_number = "+8801712345678",
withdraw_id ="012458756",
webhook_url = "https://example.com/withdraw-callback"
};
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("X-Authorization", "pk_test_123...");
client.DefaultRequestHeaders.Add("X-Authorization-Secret", "sk_test_456...");
var content = new StringContent(
Newtonsoft.Json.JsonConvert.SerializeObject(payload),
Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}
}
| Header | Required | Description |
|---|---|---|
X-Authorization |
Required | Your API public key for authentication. |
X-Authorization-Secret |
Required | Your API secret key for authentication. |
Content-Type |
Required | application/json |
The following parameters are required to create a withdraw request:
| Field | Type | Description |
|---|---|---|
amount |
numeric | The amount to be transferred to the customer's MFS account. |
mfs_operator |
string | The name of the MFS operator (e.g., bKash, Nagad). |
cust_number |
string | The customer's mobile number registered with the MFS operator. |
withdraw_id |
string | The withdraw_id is unique. |
webhook_url |
string | The webhook URL where the final withdraw status notification will be sent (Withdraw Webhook). |
If the withdraw request is successfully accepted, the response will include the transaction ID (trxid). This response only confirms that the request has been accepted for processing — it is not the final transaction status. The final status (completed, rejected, etc.) will be delivered asynchronously to your provided webhook URL.
{
"status": true,
"trxid": "TRX-12345-20231010123456-5678"
}
// NOTE: `status: true` here only indicates the request was accepted.
// The final transaction status will be sent to your provided webhook URL.
If the request fails due to validation errors or insufficient merchant balance.
If the request fails due to validation errors or insufficient merchant balance.
{
"status": false,
"message": "Amount is greater than Merchant Balance"
}
| Field | Type | Description |
|---|---|---|
status |
string | Indicates whether the request was successful (success) or not (false). |
trxid |
string | The unique transaction ID for tracking the payment status. |
message |
string | A message describing the error, if the request fails. |
The Withdraw Create endpoint only confirms that your withdraw request has been accepted for processing — it does not return the final outcome. Withdraw transactions are executed asynchronously through the MFS operator (bKash, Nagad, Rocket, etc.), so the final status becomes available only after the MFS network confirms the transfer.
Use this Check Transaction Status endpoint to poll the latest status of a withdraw transaction by its trnx_id. It returns the current status (pending, success, or rejected), the amount, MFS operator, and additional information like the MFS-side transaction reference or rejection reason.
Recommendation: Instead of polling this endpoint continuously, provide a webhook_url when creating the withdraw. The system will push the final status to your webhook automatically as soon as it is available — see the Webhook section below. Use this status-check endpoint as a fallback (e.g., to reconcile missed webhooks or verify a transaction on demand).
Use this endpoint to check the status of a transaction using the trnx_id. Requires authentication via X-Authorization and X-Authorization-Secret headers. The response will include details about the transaction, such as its status, amount, and associated MFS information.
curl -X POST "https://bdpay.llc/api/v1/mfs/status_check" \
-H "X-Authorization: pk_test_123..." \
-H "X-Authorization-Secret: sk_test_456..." \
-H "Content-Type: application/json" \
-d '{
"trnx_id": "TRX-12345-20231010123456-5678"
}'
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://bdpay.llc/api/v1/mfs/status_check",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
"X-Authorization: pk_test_123...",
"X-Authorization-Secret: sk_test_456...",
"Content-Type: application/json"
),
CURLOPT_POSTFIELDS => '{
"trnx_id": "TRX-12345-20231010123456-5678"
}'
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
import requests
url = "https://bdpay.llc/api/v1/mfs/status_check"
headers = {
"X-Authorization": "pk_test_123...",
"X-Authorization-Secret": "sk_test_456...",
"Content-Type": "application/json"
}
payload = {
"trnx_id": "TRX-12345-20231010123456-5678"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://bdpay.llc/api/v1/mfs/status_check";
const headers = {
"X-Authorization": "pk_test_123...",
"X-Authorization-Secret": "sk_test_456...",
"Content-Type": "application/json"
};
const payload = {
trnx_id: "TRX-12345-20231010123456-5678"
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var url = "https://bdpay.llc/api/v1/mfs/status_check";
var payload = new
{
trnx_id = "TRX-12345-20231010123456-5678"
};
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("X-Authorization", "pk_test_123...");
client.DefaultRequestHeaders.Add("X-Authorization-Secret", "sk_test_456...");
var content = new StringContent(
Newtonsoft.Json.JsonConvert.SerializeObject(payload),
Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}
}
| Header | Required | Description |
|---|---|---|
X-Authorization |
Required | Your API public key for authentication. |
X-Authorization-Secret |
Required | Your API secret key for authentication. |
Content-Type |
Required | application/json |
| Field | Type | Description |
|---|---|---|
trnx_id |
string | Transaction ID you want to check the status of. |
If the transaction is found, the response will include the transaction details and status.
{
"status": "true",
"data": {
"withdraw_number": "01448898189",
"mfs_operator": "bkash",
"amount": "20",
"msg": "[ Carrier info, Amount too low to transact., OK]",
"status": "pending"
}
}
Details about the possible statuses: pending, success, rejected.
If the transaction is not found or the trnx_id is invalid.
Details about the possible statuses:pending,success,rejected.
If the transaction is not found or the trnx_id is invalid.
{
"status": "false",
"message": "This TRXID not available"
}
| Field | Type | Description |
|---|---|---|
status |
string | Indicates whether the request was successful (true) or not (false). |
data |
object | Contains the transaction details if the request is successful. |
withdraw_number |
string | The customer's mobile number associated with the transaction. |
mfs_operator |
string | The MFS operator used for the transaction (e.g., bKash). |
amount |
numeric | The amount of the transaction. |
msg |
string | Additional message about the transaction. |
status (nested) |
string | The current status of the transaction (pending, success, or rejected). |
The Withdraw Webhook lets you receive the final status of a withdraw transaction automatically, without polling the status-check endpoint. When a withdraw transaction is success or rejected, the system sends a POST request in JSON format to the webhook_url you provided in the Withdraw Create request.
Include webhook_url in your Withdraw Create request.
The MFS operator processes the withdraw and returns success or rejected.
System sends a POST request with final status to your webhook URL.
The following JSON payload will be sent as a POST request to your webhook_url when the withdraw is success:
{
"status": "true",
"signature": "6294408b326cf940cad20816cda5aa96c234fcabfeef49d013be6e6daeb9514e",
"data": {
"withdraw_number": "01448898189",
"mfs_operator": "bkash",
"amount": "500",
"msg": "8N7A9B2C3D",
"status": "success",
"withdraw_id": "TRX-12345-20231010123456-5678"
}
}
When the withdraw is rejected, the payload looks like:
{
"status": "true",
"signature": "6294408b326cf940cad20816cda5aa96c234fcabfeef49d013be6e6daeb9514e",
"data": {
"withdraw_number": "01448898189",
"mfs_operator": "bkash",
"amount": "500",
"msg": "Insufficient balance in MFS account",
"status": "rejected",
"withdraw_id": "TRX-12345-20231010123456-5678"
}
}
| Field | Type | Description |
|---|---|---|
status |
string | Always "true" when the webhook is dispatched. |
signature |
string | SHA-256 HMAC signature of the data object, generated using your secret key. |
data.withdraw_number |
string | The customer's mobile wallet number where the amount was sent. |
data.mfs_operator |
string | MFS operator used (e.g., bkash, nagad, rocket). |
data.amount |
numeric | Withdraw amount in BDT. |
data.msg |
string | On success: the MFS-side transaction reference (TrxID). On rejected: the rejection reason. |
data.status |
string | Final transaction status: success or rejected. |
data.withdraw_id |
string | Our unique transaction ID (trxid) returned in the Withdraw Create response. Use this to match the webhook with the original request. |
<?php
// withdraw-webhook.php — Your webhook endpoint
$payloadRaw = file_get_contents('php://input');
$payload = json_decode($payloadRaw, true);
// Your merchant secret key
$merchantSecretKey = 'YOUR_SECRET_KEY';
if ($payload && isset($payload['data']) && isset($payload['signature'])) {
// Verify the signature
$dataJson = json_encode($payload['data']);
$expectedSignature = hash_hmac('sha256', $dataJson, $merchantSecretKey);
if (!hash_equals($expectedSignature, $payload['signature'])) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
$data = $payload['data'];
$withdrawId = $data['withdraw_id']; // our trxid
$status = $data['status']; // 'success' or 'rejected'
$amount = $data['amount'];
$number = $data['withdraw_number'];
$mfs = $data['mfs_operator'];
$msg = $data['msg'];
if ($status === 'success') {
// Withdraw completed — $msg contains the MFS TrxID
// updateWithdraw($withdrawId, 'success', $msg);
} elseif ($status === 'rejected') {
// Withdraw rejected — $msg contains the reason; refund to merchant balance if needed
// updateWithdraw($withdrawId, 'rejected', $msg);
}
// Acknowledge receipt
http_response_code(200);
echo json_encode(['received' => true]);
} else {
http_response_code(400);
echo json_encode(['error' => 'Invalid payload or missing signature']);
}
success or rejected). Pending transactions do not trigger webhooks.
POST request with Content-Type: application/json.
withdraw_id (our trxid) and verify the amount before marking a withdraw complete.
200 from your webhook endpoint to acknowledge receipt.