Superchat BD
Developer Docs
v1.0
Payments API

Hosted Checkout Sessions

Create payment sessions from your server and redirect customers to complete their payment securely via bKash, Nagad, Rocket, or international cards. Amounts are settled to your workspace balance minus the platform fee.

Endpoints

MethodPathPurpose
POST/api/v1/paymentsCreate a hosted checkout session (201).
GET/api/v1/payments/:idRetrieve a payment with its fee breakdown.
GET/api/v1/payments?page=&limit=&status=List payments, newest first.
POST/api/v1/payments/:id/refundRefund a paid payment.

Create request body

FieldTypeRequiredDescription
amountnumberRequiredAmount in `currency`; must be at least 1.
success_urlstringRequiredAbsolute URL the customer returns to after paying.
cancel_urlstringRequiredAbsolute URL the customer returns to when they cancel.
currencystringOptional`BDT` (default) or `USD`. No other currency is accepted.
descriptionstringOptionalShown to the customer on the checkout page.
customerobjectOptional`{ name, email, phone }`, stored on the payment and echoed in webhooks.
metadataobjectOptionalArbitrary key/value pairs, returned unchanged in webhooks.

Field names are snake_case, and unknown fields are rejected.

The API validates strictly: successUrl, customerName and any other unrecognised field return 400 Bad Request. Send success_url / cancel_url and nest customer details under customer.

Node.js request example

const response = await fetch('https://api.superchatbd.com/api/v1/payments', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_your_api_key',
    'Content-Type': 'application/json',
    'Idempotency-Key': 'order_12345', // optional, but keeps retries safe
  },
  body: JSON.stringify({
    amount: 1500,
    currency: 'BDT',
    description: 'Pro Subscription - 1 Month',
    success_url: 'https://myshop.com/orders/12345/success',
    cancel_url: 'https://myshop.com/cart',
    customer: {
      name: 'Ashraful Islam',
      email: '[email protected]',
      phone: '01700000000',
    },
    metadata: { orderId: '12345', userId: 'usr_883' },
  }),
});

if (!response.ok) throw new Error(await response.text());

const session = await response.json();
console.log(session.checkoutUrl);
// Redirect the customer to session.checkoutUrl

Response

{
  "id": "pay_9f82d1c720b14f76bf10fa37b12d5893",
  "merchantTransactionId": "pay_9f82d1c720b14f76bf10fa37b12d5893",
  "checkoutUrl": "https://superchat.bd/checkout/pay_9f82d1c720b14f76bf10fa37b12d5893",
  "amount": 1500,
  "currency": "BDT",
  "status": "pending",          // public status: pending | completed | failed | cancelled | refunded | expired
  "rawStatus": "created",       // internal status: created | paid | ...
  "environment": "live",        // "test" for sk_test_… keys
  "isSimulated": false,
  "platformFeeAmount": 75,      // 5% platform fee
  "feePercentage": 5,
  "netAmount": 1425,            // credited to your workspace on success
  "description": "Pro Subscription - 1 Month",
  "customer": { "name": "Ashraful Islam", "email": "[email protected]", "phone": "01700000000" },
  "customerName": "Ashraful Islam",
  "customerEmail": "[email protected]",
  "customerPhone": "01700000000",
  "paymentMethod": null,
  "metadata": { "orderId": "12345", "userId": "usr_883" },
  "success_url": "https://myshop.com/orders/12345/success",
  "cancel_url": "https://myshop.com/cart",
  "paid_at": null,
  "created_at": "2026-09-20T05:00:00.000Z",
  "createdAt": "2026-09-20T05:00:00.000Z",
  "updatedAt": "2026-09-20T05:00:00.000Z"
}

Payments created with an sk_test_ key run in the sandbox: they behave identically but can be settled instantly from the sandbox simulator. Legacy snake_case aliases (checkout_url, platform_fee, platform_fee_rate, net_amount) are still returned.

Refunding a payment

Refunds can be initiated by making a POST request to /api/v1/payments/:id/refund. Only payments in the internal paid status can be refunded. A successful refund immediately debits the developer workspace balance and lifetime earnings, updates the status to refunded, and triggers a payment.refunded webhook.

const response = await fetch('https://api.superchatbd.com/api/v1/payments/pay_9f82d1c720b14f76bf10fa37b12d5893/refund', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_your_api_key',
    'Content-Type': 'application/json',
    'Idempotency-Key': 'refund_order_12345',
  },
  body: JSON.stringify({
    reason: 'Customer requested cancellation',
  }),
});

const refundedPayment = await response.json();
console.log(refundedPayment.status); // "refunded"
console.log(refundedPayment.refund);
// {
//   id: null,
//   requiresManualSettlement: true, // true for EPS / BDT
//   reason: "Customer requested cancellation"
// }

Manual settlement for BDT / EPS transactions

Bangladeshi MFS providers (bKash, Nagad, Rocket) and the EPS gateway do not provide programmatic reversal APIs. When refunding a BDT payment, the API adjusts your balance and returns requiresManualSettlement: true in the refund payload. The merchant is responsible for transferring the refund amount directly to the customer's account.

Test payments (sk_test_) cannot be refunded since no real money was transferred.

Testing in Sandbox (sk_test_...)

When creating payments with a test API key (sk_test_...), two testing paths are supported:

  • 1-Click Simulator Controls: On the hosted checkout page, click Instant Success or Simulate Fail to trigger webhooks and return immediately to your redirect URLs without opening a gateway.
  • Interactive EPS Sandbox Gateway: Click Proceed to EPS Sandbox Gateway to interact with the real EPS sandbox (sandboxpgapi.eps.com.bd) and test bKash, Nagad, and Rocket simulated payments end-to-end.

All test transactions fire HMAC-signed payment.completed webhooks exactly like live transactions. Real money is never transferred and test payments never credit live workspace balances.

Redirect URL rules

Live payments must use https:// URLs (localhost is allowed for local development).

If your API key is bound to an application that has registered redirect URIs, both URLs must share an origin with one of them — this is what stops a leaked key from turning your checkout into an open redirect.