Build

API reference

The complete charge → verify → refund lifecycle with brand-scoped keys, request fields, response shapes, rate limits and error codes.

12 min read

Base URL

Every endpoint is relative to the domain that serves your checkout — the cloud address for hosted workspaces, or your own domain when self-hosted. Requests and responses are JSON over HTTPS, and errors use the matching HTTP status code.

Three endpoints do the work: POST /api/charge, POST /api/verify-payment and POST /api/refund-payment. Webhooks are delivered to the URL you configure, and the device bridge uses POST /api/device/ingest with a device token instead of an API key.

endpoint map
POST /api/charge          create an invoice and payment URL
POST /api/verify-payment  check the final state of an invoice
POST /api/refund-payment  record a full or partial refund
POST /api/device/ingest   forward an SMS (device token, not API key)

Authentication

Every request uses a brand-scoped API key. Create keys in Developers → API keys; each key can be revoked independently and records when it was last used.

The header is RT-TAKAFLOW-API-KEY. For convenience the API also accepts x-api-key or Authorization: Bearer <key>.

bash
RT-TAKAFLOW-API-KEY: tf_live_xxxxxxxxxxxxxxxx
Content-Type: application/json

Rate limits

  • Create charge — 60 requests per minute per key.
  • Verify payment — 120 requests per minute per key.
  • Refund — 30 requests per minute per key.
  • Device ingest — 120 messages per minute per device.
  • Exceeding a limit returns 429 with Retry-After and X-RateLimit-Limit / X-RateLimit-Remaining headers. Back off and retry; do not loop.

Create a charge

  • amount — required, in BDT, minimum 1. Decimals are accepted.
  • full_name — customer name shown on the checkout.
  • email, phone — optional customer details for the receipt and CRM record.
  • description — what the customer is paying for.
  • expires_in — minutes until the payment link closes (10–1440, default 60).
  • metadata — object of strings or numbers, echoed on the invoice and webhook.
  • redirect_url, cancel_url — where the customer lands after success or abandonment.
  • webhook_url — per-invoice override for the brand webhook endpoint.
POST /api/charge
curl -X POST https://your-domain.com/api/charge \
  -H "RT-TAKAFLOW-API-KEY: tf_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "full_name": "Nusrat Jahan",
    "email": "nusrat@example.com",
    "phone": "01712345678",
    "amount": 1250,
    "description": "Annual hosting renewal",
    "expires_in": 60,
    "metadata": { "order_id": "ORD-1042", "plan": "annual" },
    "redirect_url": "https://shop.example.com/thanks",
    "cancel_url": "https://shop.example.com/cart",
    "webhook_url": "https://shop.example.com/api/takaflow"
  }'

Charge response

200 OK
{
  "status": true,
  "message": "Charge created.",
  "invoice_id": 128,
  "invoice_number": "TF-202610-4821",
  "token": "6d1c...",
  "amount": "1250.00",
  "payment_url": "https://your-domain.com/checkout/6d1c...",
  "expires_at": "2026-10-29T20:20:11.000Z"
}

Redirect the customer to payment_url, or render it as a button. invoice_id is the numeric internal id; invoice_number and token are also accepted by the verify and refund endpoints.

Verify a payment

Send invoice_id (number or number string), invoice_number or token — one value is enough. Call this from your success page and before fulfilling an order; never trust the redirect parameters on their own.

POST /api/verify-payment
curl -X POST https://your-domain.com/api/verify-payment \
  -H "RT-TAKAFLOW-API-KEY: tf_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "invoice_id": "TF-202610-4821" }'

Verify response

  • payment_status is COMPLETED, PENDING, UNPAID, REFUNDED or CANCELLED.
  • Treat only COMPLETED as paid. PENDING means a TrxID was submitted but no SMS has matched yet.
  • payment_id is what the refund endpoint expects; it is null when the invoice has no payment yet.
  • Match metadata.order_id against your own order before fulfilling — this protects against a customer reusing another invoice's URL.
200 OK
{
  "status": true,
  "payment_status": "COMPLETED",
  "invoice_id": 128,
  "invoice_number": "TF-202610-4821",
  "payment_id": 910,
  "transaction_id": "9F2K7D1QAX",
  "sender_number": "01712345678",
  "payment_method": "bkash",
  "amount": "1250.00",
  "fee": "0.00",
  "charged_amount": "1250.00",
  "metadata": { "order_id": "ORD-1042" },
  "paid_at": "2026-10-29T14:20:11.000Z"
}

Refund a payment

payment_id is the numeric id returned by verify-payment. amount is optional and defaults to the full remaining balance; partial and repeated refunds are supported. NaklaPay records the refund and fires payment.refunded. Because funds live in your MFS account, the actual money movement is yours to perform; the record keeps the audit trail complete.

POST /api/refund-payment
curl -X POST https://your-domain.com/api/refund-payment \
  -H "RT-TAKAFLOW-API-KEY: tf_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "payment_id": 910, "amount": 1250 }'

Errors

  • 401 — missing, invalid or revoked API key.
  • 404 — invoice or payment not found on this brand.
  • 409 — payment is not in a refundable state.
  • 422 — validation failure; the message names the problem.
  • 429 — rate limit exceeded; retry after the Retry-After delay.
  • 400 — malformed JSON or a refund rejected by the balance rules.
  • Errors return { "status": false, "message": "…" } with the matching HTTP code.

Testing without money

Open the public demo checkout to run the full verify loop with seeded data: submit the demo TrxID and the invoice completes through the same matching engine production uses. When you register a workspace, it also ships with sample payments, SMS records and invoices that you can clear in Settings.

Keep sandbox experiments on sample invoices. A real charge moves through your own MFS account, so test with a small amount from a second phone when you connect your first gateway.

Open the live demo