InstaPay BD Developer Documentation

Integrate payment checkout and verify transactions securely with a simple server-side flow.

Developer reference

Introduction

InstaPay BD provides payment automation and transaction verification tools for websites, bots and backend applications.

Getting started

For payment checkout, use the invoice ID returned by InstaPay. For direct payment verification, customers enter only a TxID; your server supplies the expected amount and method. Keep credentials server-side.

Payment Gateway API

Create a checkout link and verify the returned invoice Transaction ID. The customer never needs to enter your API credentials.

Endpoints

POSThttps://pay.instapaybd.com/api/payment/create
POSThttps://pay.instapaybd.com/api/payment/verify
Payment Gateway API: create a checkout, then verify its invoice transaction_id. For a separately submitted bank/mobile/Binance transaction, use the Transaction Verification API below.

Parameters & Headers

FieldRequiredDescription
amountCreate onlyPayable amount from your saved order/invoice. Never trust an amount submitted by the customer.
success_urlYesSuccessful payment redirect URL.
cancel_urlYesCancelled payment redirect URL.
metadataNoOptional JSON metadata.
transaction_idVerify onlyInstaPay checkout invoice Transaction ID (Payment Verify endpoint).
HeaderValue
Content-Typeapplication/json
API-KEYAPI/App Key
SECRET-KEYSecret Key
BRAND-KEYBrand Key

Payment Integration

Copy-ready examples. The invoice amount is set by your server; the verification request uses the invoice Transaction ID.

Create Payment

Set the payable amount on your server and send your customer to the returned payment URL.

Use the amount from your saved order. A customer does not need to enter an amount or your API credentials.

cURL
curl --request POST 'https://pay.instapaybd.com/api/payment/create' \ --header 'Content-Type: application/json' \ --header 'API-KEY: YOUR_API_KEY' \ --header 'SECRET-KEY: YOUR_SECRET_KEY' \ --header 'BRAND-KEY: YOUR_BRAND_KEY' \ --data '{ "amount":"900.000", "success_url":"https://yourdomain.com/payment/success", "cancel_url":"https://yourdomain.com/payment/cancel" }'
PHP cURL
<?php$order = [ 'amount' => '900.000', 'success_url' => 'https://yourdomain.com/payment/success', 'cancel_url' => 'https://yourdomain.com/payment/cancel',];$ch = curl_init('https://pay.instapaybd.com/api/payment/create');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 25, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'API-KEY: YOUR_API_KEY', 'SECRET-KEY: YOUR_SECRET_KEY', 'BRAND-KEY: YOUR_BRAND_KEY', ], CURLOPT_POSTFIELDS => json_encode($order),]);$result = curl_exec($ch);$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);$error = curl_error($ch);curl_close($ch);if ($result === false) { throw new RuntimeException($error);}$data = json_decode($result, true);if ($httpCode >= 200 && $httpCode < 300 && !empty($data['payment_url'])) { $paymentUrl = $data['payment_url']; echo $paymentUrl;} else { echo $result;}
PHP Guzzle
<?php$client = new \GuzzleHttp\Client(['timeout' => 25]);$response = $client->post('https://pay.instapaybd.com/api/payment/create', [ 'headers' => [ 'API-KEY' => 'YOUR_API_KEY', 'SECRET-KEY' => 'YOUR_SECRET_KEY', 'BRAND-KEY' => 'YOUR_BRAND_KEY', ], 'json' => [ 'amount' => '900.000', 'success_url' => 'https://yourdomain.com/payment/success', 'cancel_url' => 'https://yourdomain.com/payment/cancel', ],]);$data = json_decode((string) $response->getBody(), true);$paymentUrl = $data['payment_url'] ?? null;var_dump($paymentUrl);
Python
import requestsorder = { "amount": "900.000", "success_url": "https://yourdomain.com/payment/success", "cancel_url": "https://yourdomain.com/payment/cancel",}response = requests.post( "https://pay.instapaybd.com/api/payment/create", headers={ "API-KEY": "YOUR_API_KEY", "SECRET-KEY": "YOUR_SECRET_KEY", "BRAND-KEY": "YOUR_BRAND_KEY", }, json=order, timeout=25,)response.raise_for_status()data = response.json()print(data.get("payment_url"))
Node.js
const order = { amount: '900.000', success_url: 'https://yourdomain.com/payment/success', cancel_url: 'https://yourdomain.com/payment/cancel',};const response = await fetch('https://pay.instapaybd.com/api/payment/create', { method: 'POST', headers: { 'Content-Type': 'application/json', 'API-KEY': 'YOUR_API_KEY', 'SECRET-KEY': 'YOUR_SECRET_KEY', 'BRAND-KEY': 'YOUR_BRAND_KEY', }, body: JSON.stringify(order), signal: AbortSignal.timeout(25000),});const data = await response.json();if (!response.ok) throw new Error(data.message || 'Create failed');console.log(data.payment_url);
Go
package mainimport ( "bytes" "fmt" "io" "net/http" "time")func main() { payload := []byte(`{"amount":"900.000","success_url":"https://yourdomain.com/payment/success","cancel_url":"https://yourdomain.com/payment/cancel"}`) req, err := http.NewRequest("POST", "https://pay.instapaybd.com/api/payment/create", bytes.NewReader(payload)) if err != nil { panic(err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("API-KEY", "YOUR_API_KEY") req.Header.Set("SECRET-KEY", "YOUR_SECRET_KEY") req.Header.Set("BRAND-KEY", "YOUR_BRAND_KEY") client := &http.Client{Timeout: 25 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { panic(err) } fmt.Println(string(body))}

Response

The successful response includes a payment_url for redirecting the customer.

FieldPurpose
statusCreation request result
messageMessage from the API
payment_urlCustomer checkout URL
Save your order/invoice amount in your own database before creating the checkout. Do not treat payment_url as proof of payment.

Payment Verify

Send the checkout invoice Transaction ID only. Match the response against your saved invoice before marking it paid.

Easy flow: The customer provides the Transaction ID. Your backend sends that ID to this Payment Gateway Verify endpoint and compares the returned amount with its saved invoice. This endpoint does not accept an amount or method parameter for extra matching.
cURL
curl --request POST 'https://pay.instapaybd.com/api/payment/verify' \ --header 'Content-Type: application/json' \ --header 'API-KEY: YOUR_API_KEY' \ --header 'SECRET-KEY: YOUR_SECRET_KEY' \ --header 'BRAND-KEY: YOUR_BRAND_KEY' \ --data '{"transaction_id":"OVKPXW165414"}'
PHP cURL
<?php$invoice = [ 'transaction_id' => 'OVKPXW165414', 'amount' => '900.000',];$ch = curl_init('https://pay.instapaybd.com/api/payment/verify');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 25, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'API-KEY: YOUR_API_KEY', 'SECRET-KEY: YOUR_SECRET_KEY', 'BRAND-KEY: YOUR_BRAND_KEY', ], CURLOPT_POSTFIELDS => json_encode([ 'transaction_id' => $invoice['transaction_id'], ]),]);$body = curl_exec($ch);$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);$error = curl_error($ch);curl_close($ch);if ($body === false) throw new RuntimeException($error);$data = json_decode($body, true);$paid = $httpCode >= 200 && $httpCode < 300 && ($data['status'] ?? '') === 'COMPLETED' && (string) ($data['transaction_id'] ?? '') === $invoice['transaction_id'] && isset($data['amount']) && is_numeric($data['amount']) && number_format((float) $data['amount'], 3, '.', '') === number_format((float) $invoice['amount'], 3, '.', '');if ($paid) { echo 'Payment verified';} else { echo 'Payment not verified';}
PHP Guzzle
<?php$invoiceId = 'OVKPXW165414';$expectedAmount = '900.000';$client = new \GuzzleHttp\Client(['timeout' => 25]);$response = $client->post('https://pay.instapaybd.com/api/payment/verify', [ 'headers' => [ 'API-KEY' => 'YOUR_API_KEY', 'SECRET-KEY' => 'YOUR_SECRET_KEY', 'BRAND-KEY' => 'YOUR_BRAND_KEY', ], 'json' => ['transaction_id' => $invoiceId],]);$data = json_decode((string) $response->getBody(), true);$paid = ($data['status'] ?? '') === 'COMPLETED' && ($data['transaction_id'] ?? '') === $invoiceId && isset($data['amount']) && is_numeric($data['amount']) && number_format((float) $data['amount'], 3, '.', '') === number_format((float) $expectedAmount, 3, '.', '');var_dump($paid);
Python
from decimal import Decimalimport requestsinvoice_id = "OVKPXW165414"invoice_amount = Decimal("900.000")response = requests.post( "https://pay.instapaybd.com/api/payment/verify", headers={ "API-KEY": "YOUR_API_KEY", "SECRET-KEY": "YOUR_SECRET_KEY", "BRAND-KEY": "YOUR_BRAND_KEY", }, json={"transaction_id": invoice_id}, timeout=25,)response.raise_for_status()data = response.json()paid = ( data.get("status") == "COMPLETED" and data.get("transaction_id") == invoice_id and data.get("amount") is not None and Decimal(str(data["amount"])) == invoice_amount)print("Payment verified" if paid else "Payment not verified")
Node.js
const invoice = { transactionId: 'OVKPXW165414', amount: '900.000',};const response = await fetch('https://pay.instapaybd.com/api/payment/verify', { method: 'POST', headers: { 'Content-Type': 'application/json', 'API-KEY': 'YOUR_API_KEY', 'SECRET-KEY': 'YOUR_SECRET_KEY', 'BRAND-KEY': 'YOUR_BRAND_KEY', }, body: JSON.stringify({ transaction_id: invoice.transactionId }), signal: AbortSignal.timeout(25000),});const data = await response.json();const paid = response.ok && data.status === 'COMPLETED' && data.transaction_id === invoice.transactionId && data.amount != null && Number.isFinite(Number(data.amount)) && Math.round(Number(data.amount) * 1000) === Math.round(Number(invoice.amount) * 1000);console.log(paid ? 'Payment verified' : 'Payment not verified');
Go
package mainimport ( "bytes" "encoding/json" "fmt" "io" "net/http" "time")func main() { invoiceID := "OVKPXW165414" req, err := http.NewRequest("POST", "https://pay.instapaybd.com/api/payment/verify", bytes.NewBufferString(`{"transaction_id":"OVKPXW165414"}`)) if err != nil { panic(err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("API-KEY", "YOUR_API_KEY") req.Header.Set("SECRET-KEY", "YOUR_SECRET_KEY") req.Header.Set("BRAND-KEY", "YOUR_BRAND_KEY") client := &http.Client{Timeout: 25 * time.Second} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { panic(err) } var data struct { Status string `json:"status"`; TransactionID string `json:"transaction_id"`; Amount string `json:"amount"` } if err := json.Unmarshal(body, &data); err != nil { panic(err) } paid := res.StatusCode == 200 && data.Status == "COMPLETED" && data.TransactionID == invoiceID && data.Amount == "900.000" fmt.Println("Verified:", paid)}

Sample Completed Response

JSON
{ "cus_name": "John Doe", "cus_email": "[email protected]", "amount": "900.000", "transaction_id": "OVKPXW165414", "metadata": {}, "payment_method": "bkash", "status": "COMPLETED"}
Payment rule: Mark an invoice paid only after status === "COMPLETED", its Transaction ID matches your invoice, and the amount matches your saved payable amount. A PENDING response is not success. Check the payment method too when your invoice requires a specific gateway.

Different API: For a Binance Order ID submitted by a customer, use /api/v1/transaction/verify with the Brand Key; the backend should add the expected USDT amount and method: "binance" from the saved order.

Modules & Downloads

WooCommerce

WordPress WooCommerce integration.

Download

WHMCS

WHMCS payment integration module.

Download

SMM Panel

SMM Panel payment module.

Download

Android App

Download the official InstaPay BD Android application.

Download App

Transaction Verification API

Customers enter only the TxID. Your server can include its saved expected amount and payment method for stricter Stored Data verification.

Simple Integration

Ask the customer for Transaction ID only. Use your saved order data on the backend.

01Customer submits TxIDNo amount or method input required
02Server adds expected valuesAmount & method from the saved order
03API verifiesComplete only on a verified, matching response

Customer input

Transaction ID only
{"transaction_id":"M_P_71505104267788288"}

Backend API request

Server adds saved values
{ "transaction_id":"M_P_71505104267788288", "amount":"5.25000000", "method":"binance"}
Binance: Compare the expected USDT amount (not the BDT invoice conversion) when using Stored Data verification. A PENDING response is not successful payment.

Endpoint

Verify payments from your account's Stored Data.

POST https://instapaybd.com/api/v1/transaction/verify

Only transaction_id is required. Add amount and method if needed.

Authentication

HeaderValue
API-KEYYour Brand Key
Content-Typeapplication/json

Request Body

Choose one request format. All provided fields must match.

JSON REQUEST
{ "transaction_id": "DIJ1N1TWAB"}
JSON REQUEST
{ "transaction_id": "DIJ1N1TWAB", "amount": 500}
JSON REQUEST
{ "transaction_id": "DIJ1N1TWAB", "method": "bkash"}
JSON REQUEST
{ "transaction_id": "DIJ1N1TWAB", "amount": 500, "method": "bkash"}
Fields: transaction_id (required), amount (optional), method (optional). Invalid fields return HTTP 422.

Binance (USDT)

Use the same endpoint with method binance. Amount is in USDT.

JSON REQUEST · BINANCE
{ "transaction_id": "M_P_71505104267788288", "amount": "5.25000000", "method": "binance"}

If Binance data is still syncing, the API may return PENDING with retry_after. A payment can be verified only once.

Verification Status

StatusVerifiedCredit
COMPLETEDYes1
PENDINGNo0
MISMATCHNo0
ALREADY_USEDNo0
NOT_FOUNDNo0

One credit is deducted only on a first successful verification.

Response Examples

JSON RESPONSE · COMPLETED
{ "success": true, "verified": true, "status": "COMPLETED", "credit_charged": 1, "remaining_credit": 999, "transaction": { "transaction_id": "DIJ1N1TWAB", "amount": "500.000", "currency": "BDT", "payment_method": "bkash" }}
JSON RESPONSE · PENDING
{ "success": false, "verified": false, "status": "PENDING", "credit_charged": 0, "remaining_credit": 1000, "retry_after": 90, "message": "Binance payment is being synchronized. Retry with the same Transaction ID."}
JSON RESPONSE · MISMATCH
{ "success": false, "verified": false, "status": "MISMATCH", "error": "parameter_mismatch", "mismatched_fields": ["amount"], "credit_charged": 0, "remaining_credit": 1000, "message": "One or more supplied parameters do not match the Stored Data transaction."}
JSON RESPONSE · ALREADY_USED
{ "success": false, "verified": false, "status": "ALREADY_USED", "credit_charged": 0, "remaining_credit": 999, "message": "This Transaction ID has already been used."}
JSON RESPONSE · NOT_FOUND
{ "success": false, "verified": false, "status": "NOT_FOUND", "credit_charged": 0, "remaining_credit": 1000, "message": "Transaction not found in Stored Data for this Brand Key."}

Integration Examples

Quick start: only transaction_id is required. For deposit crediting, send amount and method too.

cURL
curl --request POST 'https://instapaybd.com/api/v1/transaction/verify' \ --header 'Content-Type: application/json' \ --header 'API-KEY: YOUR_BRAND_KEY' \ --data '{"transaction_id":"DIJ1N1TWAB"}'
PHP
<?php$payload = ['transaction_id' => 'DIJ1N1TWAB'];$ch = curl_init('https://instapaybd.com/api/v1/transaction/verify');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 25, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'API-KEY: YOUR_BRAND_KEY' ], CURLOPT_POSTFIELDS => json_encode($payload)]);$body = curl_exec($ch);if ($body === false) { throw new RuntimeException(curl_error($ch));}$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);curl_close($ch);$result = json_decode($body, true);$verified = $httpCode >= 200 && $httpCode < 300 && ($result['verified'] ?? false) === true && ($result['status'] ?? '') === 'COMPLETED';
Python
import requestsresponse = requests.post( 'https://instapaybd.com/api/v1/transaction/verify', headers={'API-KEY': 'YOUR_BRAND_KEY'}, json={'transaction_id': 'DIJ1N1TWAB'}, timeout=25)result = response.json()verified = ( response.ok and result.get('verified') is True and result.get('status') == 'COMPLETED')
Node.js
const response = await fetch('https://instapaybd.com/api/v1/transaction/verify', { method: 'POST', headers: { 'Content-Type': 'application/json', 'API-KEY': 'YOUR_BRAND_KEY' }, body: JSON.stringify({ transaction_id: 'DIJ1N1TWAB' }), signal: AbortSignal.timeout(25000)});const result = await response.json();const verified = response.ok && result.verified === true && result.status === 'COMPLETED';
Security: Keep Brand Keys server-side. For adding balance, provide transaction_id, amount and method, and require verified === true with status === "COMPLETED".