Base URL: https://biswasto.com/api/v1
Every request needs these headers, built from your API key and secret:
| Header | Value |
|---|---|
X-API-Key | Your API key |
X-Timestamp | Current Unix time, within 5 minutes of ours |
X-Nonce | A random string, 16–64 characters, unique per request |
X-Signature | See below |
Signature payload: timestamp + "." + nonce + "." + METHOD + "." + path + "." + sha256(body)
Sign it with HMAC-SHA256 using your secret, and send the hex digest as X-Signature.
TIMESTAMP=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY='{"amount":500,"order_id":"ORDER-1001","payment_method":"bkash_personal"}'
BODY_HASH=$(echo -n "$BODY" | sha256sum | cut -d' ' -f1)
PAYLOAD="$TIMESTAMP.$NONCE.POST./api/v1/payment/create.$BODY_HASH"
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "YOUR_SECRET" | cut -d' ' -f2)
curl -X POST https://biswasto.com/api/v1/payment/create \
-H "X-API-Key: YOUR_KEY" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGNATURE" \
-H "Idempotency-Key: $(openssl rand -hex 16)" \
-H "Content-Type: application/json" \
-d "$BODY"
$timestamp = time();
$nonce = bin2hex(random_bytes(16));
$body = json_encode(['amount' => 500, 'order_id' => 'ORDER-1001', 'payment_method' => 'bkash_personal']);
$payload = "$timestamp.$nonce.POST./api/v1/payment/create." . hash('sha256', $body);
$signature = hash_hmac('sha256', $payload, 'YOUR_SECRET');
$ch = curl_init('https://biswasto.com/api/v1/payment/create');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
'X-API-Key: YOUR_KEY',
"X-Timestamp: $timestamp",
"X-Nonce: $nonce",
"X-Signature: $signature",
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
'Content-Type: application/json',
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
POST /payment/create · requires Idempotency-Key
{
"amount": 500.00,
"currency": "BDT",
"order_id": "ORDER-1001",
"payment_method": "bkash_personal",
"customer_name": "Rahim",
"redirect_url": "https://yoursite.com/thanks",
"expires_in": 900
}
Response:
{
"success": true,
"data": {
"payment_id": "PAY-20260830-3C91",
"request_id": "REQ-20260830-8F72A1",
"status": "PENDING",
"checkout_url": "https://biswasto.com/pay/REQ-20260830-8F72A1"
}
}
GET /payment/status/{payment_id} — lightweight, safe to poll
GET /payment/{payment_id} — full details
GET /payments?status=VERIFIED&from=2026-08-01&to=2026-08-31&page=1
POST /payment/{payment_id}/cancel
Configure a URL in your dashboard. We POST an event whenever a payment settles.
| Header | Value |
|---|---|
X-Webhook-Id | Unique per delivery — use it to ignore duplicates |
X-Webhook-Timestamp | Unix time the request was sent |
X-Webhook-Signature | sha256=HMAC(secret, timestamp + "." + raw_body) |
{
"event": "payment.verified",
"payment_id": "PAY-20260830-3C91",
"order_id": "ORDER-1001",
"amount": 500.00,
"status": "VERIFIED",
"transaction_reference": "ABC123",
"verified_at": "2026-08-30T18:32:11+06:00"
}
We retry a failed delivery for up to 24 hours: after 1, 5, 15, 60, 360 and 1440 minutes.
| Code | HTTP |
|---|---|
INVALID_SIGNATURE | 401 |
EXPIRED_TIMESTAMP | 401 |
REPLAYED_NONCE | 401 |
MERCHANT_SUSPENDED | 403 |
PAYMENT_NOT_FOUND | 404 |
DUPLICATE_TRANSACTION | 409 |
DUPLICATE_ORDER | 409 |
REQUEST_IN_PROGRESS | 409 |
VALIDATION_ERROR | 422 |
AMOUNT_OUT_OF_RANGE | 422 |
IDEMPOTENCY_KEY_REUSED | 422 |
RATE_LIMIT_EXCEEDED | 429 |
PROVIDER_UNAVAILABLE | 502 |
CIRCUIT_OPEN | 503 |
Create a sandbox API key from your dashboard. Sandbox payments never touch a real provider — you can approve or reject them yourself from the merchant panel's manual review queue to test both outcomes.