Documentationv3.0
Zero-SDK Direct HTTP REST Architecture

Production MFS Payment
Integration Reference.

Integrate SwapnoPay directly using standard HTTPS REST requests, HMAC-SHA256 webhooks, and the hosted Checkout Widget (`widget.html`). No third-party SDK packages or CMS plugins required.

Production Guideline

Platform Mechanism & Architecture

SwapnoPay unifies carrier MFS SMS verification on Android, merchant databases, and web checkouts into a high-speed settlement pipeline.

bolt Atomic Pattern Matching

Merchant Android workers intercept raw carrier MFS SMS (bKash, Nagad, Rocket, Upay) and perform atomic regex extraction of Transaction ID, amount, and sender phone.

lock Central HMAC & Ledger

Platform Owner Admin Supabase database manages API key peppered HMAC digests, platform fee accounting, idempotency guards, and centralized payment telemetry.

rss_feed Real-Time WebSockets

Express.js + Socket.io server emits instant payment_status events (PAID, FAILED, CANCELLED) to listening web checkout widgets.

System Sequence & Flowchart

End-to-end payment lifecycle from checkout initialization to carrier match and webhook dispatch.

┌─────────────────┐       ┌────────────────────┐       ┌────────────────────────┐
│  Customer Web   │       │  SwapnoPay Backend │       │ Merchant Android Phone │
│ Checkout Widget │       │ (Node + Socket.io) │       │ (Carrier SMS Receiver) │
└────────┬────────┘       └─────────┬──────────┘       └───────────┬────────────┘
         │                          │                              │
 1. Join Order Room                 │                              │
         ├─────────────────────────>│                              │
         │                          │                              │
 2. Customer Sends Money (bKash)    │                              │
         │                          │                              │
 3. Android Worker Intercepts SMS   │                              │
         │                          │       4. Regex Pattern Match │
         │                          │          TxID, Amount, Phone │
         │                          │<─────────────────────────────┤
         │                          │ 5. POST /v1/payment/verify   │
         │                          │                              │
 6. Socket.io 'payment_status'      │                              │
    (Status = PAID, Redirect URL)   │                              │
         │<─────────────────────────┤                              │
         │                          │                              │
 7. Instant Redirect to Success Page│                              │
         │                          │                              │
          

Authentication & Headers

Authenticate API calls using your Secret Key and protect against duplicate transactions with idempotency.

Header Name Type Description
X-Admin-Secret string Your merchant API Secret Key starting with sk_live_...
Idempotency-Key string (UUID) Unique client request token to guarantee each charge is executed exactly once.
Content-Type string Must be set to application/json.

Core API Endpoints Reference

Production HTTP endpoints for payment creation, instant verification, status queries, and dynamic hosted forms.

POST /v1/payment/create

Creates a new payment checkout session and generates the hosted payment link.

{
  "order_id": "ORD-2026-9812",
  "amount": 1250.00,
  "currency": "BDT",
  "customer_name": "Tanvir Hasan",
  "customer_phone": "01712963652",
  "customer_email": "tanvir@example.com",
  "payment_method": "bKash",
  "redirect_url": "https://merchant.example.com/checkout/success",
  "cancel_url": "https://merchant.example.com/checkout/cancel"
}
Response (200 OK):
{
  "status": "SUCCESS",
  "code": 200,
  "data": {
    "order_id": "ORD-2026-9812",
    "payment_url": "https://pay.swapnopay.top/pay/ORD-2026-9812",
    "assigned_gateway_number": "01784992118",
    "payable_amount": 1250.00,
    "expires_at": "2026-09-07T21:15:00Z"
  }
}
POST /v1/payment/verify

Invoked by the carrier SMS receiver to verify transaction parameters and settle order.

{
  "order_id": "ORD-2026-9812",
  "tran_id": "9H8B7G6F5E",
  "sender_phone": "01712963652",
  "amount": 1250.00,
  "payment_method": "bKash"
}
GET /v1/payment/status/{orderId}

Inspect live settlement status (PAID, PENDING, EXPIRED).

POST /v1/hosted-form/submit

Dynamic hosted form submission supporting custom date pickers, dropdowns, and file upload attachments.

⚠️ API Error Codes Reference
Error Code HTTP Description & Resolution
ERR_INVALID_HMAC 401 HMAC-SHA256 signature verification failed. Check your webhook secret.
ERR_ORDER_EXPIRED 400 Order payment lifetime (default 10 min) elapsed before payment completion.
ERR_DUPLICATE_IDEMPOTENCY 409 Request with this Idempotency-Key was already processed. Read cached order.
ERR_INSUFFICIENT_AMOUNT 422 Customer paid less than order invoice. Transaction flagged for manual appeal.
ERR_GATEWAY_OFFLINE 503 No Android receiver phone currently online for requested payment gateway.

Webhooks & HMAC-SHA256 Signature Security

SwapnoPay signs all outbound webhook notifications with HMAC-SHA256 in the X-SwapnoPay-Signature header (t=<timestamp>,v1=<hmac>).

Node.js Signature Verification (Zero SDK — Built-in node:crypto):

const crypto = require('node:crypto');

function verifySwapnoPayWebhook(rawBodyString, signatureHeader, webhookSecret) {
  const parts = Object.fromEntries(
    String(signatureHeader || '').split(',').map(p => p.trim().split('='))
  );
  if (!parts.t || !parts.v1) return false;

  // Replay protection: reject timestamps older than 5 minutes (300s)
  if (Math.abs(Math.floor(Date.now() / 1000) - Number(parts.t)) > 300) return false;

  const expected = crypto
    .createHmac('sha256', webhookSecret)
    .update(`${parts.t}.${rawBodyString}`, 'utf8')
    .digest('hex');

  return crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(parts.v1, 'hex'));
}

Python Signature Verification (Built-in hmac & hashlib):

import hmac
import hashlib
import time

def verify_swapnopay_webhook(raw_body: str, signature_header: str, secret: str) -> bool:
    parts = dict(item.strip().split("=", 1) for item in signature_header.split(",") if "=" in item)
    ts = int(parts.get("t", "0"))
    sig = parts.get("v1", "")
    if not ts or not sig or abs(int(time.time()) - ts) > 300:
        return False
    signed_payload = f"{ts}.{raw_body}".encode("utf-8")
    expected = hmac.new(secret.encode("utf-8"), signed_payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

Enterprise Production Deployment & Go-Live Guideline

Mandatory production architecture, security controls, Android SIM Worker configuration, and reconciliation checklist.

Zero-SDK Standard

architecture 1. Direct HTTP REST + Hosted Widget

SwapnoPay requires zero third-party SDKs or CMS plugins. Your backend creates orders via standard HTTPS POST /v1/payment/create (or /v1/developer/sandbox/order) and directs customers to the hosted checkout URL or embeds widget.html inside an iframe.

key 2. Credential Isolation & Secret Storage

Store sk_live_... and whsec_... strictly in backend environment variables. Never bundle secret keys inside frontend SPAs, Android/iOS client apps, or public repositories.

smartphone 3. Dedicated Android SIM Bridge Setup

Run the SwapnoPay Merchant Android App on a dedicated device holding your active bKash (16247), Nagad (16167), Rocket (16216), or Upay (16268) SIMs. Grant RECEIVE_SMS permission and disable Android Battery Optimization so the foreground socket stays connected 24/7.

verified_user 4. Idempotent Order Fulfillment

Enforce a UNIQUE database constraint on both order_id and carrier trx_id in your database. Always verify the X-SwapnoPay-Signature header and confirm the paid amount matches your invoice total before fulfilling an order.

Direct HTTP REST & Checkout Widget Examples (No SDK Required)

Copy-paste production integrations using standard built-in HTTP clients for your stack.

🟢 Node.js 18+ (Native fetch — Zero NPM Dependencies)
const crypto = require('node:crypto');

async function createSwapnoPayOrder() {
  const response = await fetch('https://pay.swapnopay.top/v1/payment/create', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer sk_live_your_api_secret',
      'Idempotency-Key': crypto.randomUUID()
    },
    body: JSON.stringify({
      order_id: 'ORD-2026-9812',
      amount: 1250.00,
      customer_phone: '01712963652',
      payment_method: 'bKash',
      redirect_url: 'https://mysite.com/success',
      webhook_url: 'https://mysite.com/api/webhooks/swapnopay'
    })
  });

  if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  const result = await response.json();
  console.log('Redirect checkout URL:', result.data.payment_url);
}
code Python (Standard requests)
import requests
import uuid

response = requests.post(
    "https://pay.swapnopay.top/v1/payment/create",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer sk_live_your_api_secret",
        "Idempotency-Key": str(uuid.uuid4())
    },
    json={
        "order_id": "ORD-2026-9812",
        "amount": 1250.00,
        "customer_phone": "01712963652",
        "payment_method": "bKash",
        "redirect_url": "https://mysite.com/success",
        "webhook_url": "https://mysite.com/api/webhooks/swapnopay"
    },
    timeout=15
)
response.raise_for_status()
print(response.json())
code PHP 8+ (Native cURL)
<?php
$ch = curl_init('https://pay.swapnopay.top/v1/payment/create');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_TIMEOUT        => 15,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        'Authorization: Bearer sk_live_your_api_secret',
        'Idempotency-Key: ' . bin2hex(random_bytes(16))
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'order_id'       => 'ORD-2026-9812',
        'amount'         => 1250.00,
        'customer_phone' => '01712963652',
        'payment_method' => 'bKash',
        'redirect_url'   => 'https://mysite.com/success',
        'webhook_url'    => 'https://mysite.com/api/webhooks/swapnopay'
    ])
]);
$response = curl_exec($ch);
curl_close($ch);
print_r(json_decode($response, true));
?>
phone_android Kotlin (Standard OkHttp)
val client = OkHttpClient()
val json = JSONObject().apply {
    put("order_id", "ORD-2026-9812")
    put("amount", 1250.00)
    put("customer_phone", "01712963652")
    put("payment_method", "bKash")
    put("redirect_url", "https://mysite.com/success")
}
val request = Request.Builder()
    .url("https://pay.swapnopay.top/v1/payment/create")
    .addHeader("Authorization", "Bearer sk_live_your_api_secret")
    .addHeader("Idempotency-Key", java.util.UUID.randomUUID().toString())
    .post(json.toString().toRequestBody("application/json".toMediaType()))
    .build()
client.newCall(request).execute().use { response ->
    println(response.body?.string())
}
web HTML Hosted Checkout Widget (iframe + postMessage)
<iframe
  src="https://pay.swapnopay.top/widget.html?merchant_id=YOUR_MERCHANT_UUID&amount=1250.00&order_id=ORD-2026-9812"
  width="100%"
  height="620"
  style="border:none; border-radius:16px; max-width:480px;"
  allow="clipboard-write">
</iframe>