Withdraw API

Send payouts to customer MFS wallets (bKash, Nagad, Rocket, Upay) via the v1 Withdraw API.

v1 Withdraw

Withdraw API

Withdraw funds directly to customer mobile wallets via bKash, Nagad, Rocket, and more — instantly and automatically.

Automated Withdrawal System

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.

Create Withdraw

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.

Endpoint

POST /api/v1/mfs/create

HTTP Request Examples

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);
                            }
                        }
                    }

Request Headers

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

Request Parameters

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

Response Examples

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"
}

Response Field Details

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.

Check Transaction Status

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.

Endpoint

POST /api/v1/mfs/status_check

HTTP Request Examples

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);
                            }
                        }
                    }

Request Headers

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

Request Parameters

Field Type Description
trnx_id string Transaction ID you want to check the status of.

Response Examples

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"
}

Response Field Details

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

Webhook

POST

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.

How It Works

1

Create Withdraw

Include webhook_url in your Withdraw Create request.

2

MFS Processes

The MFS operator processes the withdraw and returns success or rejected.

3

Receive Notification

System sends a POST request with final status to your webhook URL.

Webhook Payload

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"
    }
}

Payload Fields

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.

Webhook Handler Example (PHP)

<?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']);
}

Important Notes

  • Webhooks are only sent for final statuses (success or rejected). Pending transactions do not trigger webhooks.
  • The webhook is sent as a POST request with Content-Type: application/json.
  • Your webhook endpoint must respond within 10 seconds. Requests that time out are logged as failed.
  • Always match the webhook to your records by withdraw_id (our trxid) and verify the amount before marking a withdraw complete.
  • Return HTTP 200 from your webhook endpoint to acknowledge receipt.
  • If your webhook fails or is unreachable, you can still retrieve the current status any time via the Check Transaction Status endpoint.