API documentation

Base URL: https://biswasto.com/api/v1

Authentication

Every request needs these headers, built from your API key and secret:

HeaderValue
X-API-KeyYour API key
X-TimestampCurrent Unix time, within 5 minutes of ours
X-NonceA random string, 16–64 characters, unique per request
X-SignatureSee 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.

cURL example

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"

PHP example

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

Create a payment

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

Check status

GET /payment/status/{payment_id} — lightweight, safe to poll

GET /payment/{payment_id} — full details

List payments

GET /payments?status=VERIFIED&from=2026-08-01&to=2026-08-31&page=1

Cancel a payment

POST /payment/{payment_id}/cancel

Webhooks

Configure a URL in your dashboard. We POST an event whenever a payment settles.

HeaderValue
X-Webhook-IdUnique per delivery — use it to ignore duplicates
X-Webhook-TimestampUnix time the request was sent
X-Webhook-Signaturesha256=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.

Errors

CodeHTTP
INVALID_SIGNATURE401
EXPIRED_TIMESTAMP401
REPLAYED_NONCE401
MERCHANT_SUSPENDED403
PAYMENT_NOT_FOUND404
DUPLICATE_TRANSACTION409
DUPLICATE_ORDER409
REQUEST_IN_PROGRESS409
VALIDATION_ERROR422
AMOUNT_OUT_OF_RANGE422
IDEMPOTENCY_KEY_REUSED422
RATE_LIMIT_EXCEEDED429
PROVIDER_UNAVAILABLE502
CIRCUIT_OPEN503

Sandbox

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.