Documentation menu

#Server guide

#Configuration

Option Default Notes
merchantId required Your Nagad merchant ID.
merchantPrivateKey required Your private key. Server only.
pgPublicKey required Nagad's gateway public key.
baseUrl required The API base URL from your onboarding details. No host is built in.
serverIp none Sent as X-KM-IP-V4. Set it to your whitelisted egress IP.
signatureAlgorithm SHA256 SHA1 for accounts configured that way.
sessionStore memory Use Redis, Upstash or a KV store in production.
cryptoProvider Node See Runtime compatibility.
fetch global Custom transport, for example a forward proxy.
hooks, logger none Auditing hooks; logs redact secrets and wallet numbers.

#Methods

Method Purpose
nagad.checkout.create(params) Initialize and complete. Returns { callBackUrl, paymentReferenceId, orderId }.
nagad.checkout.verify({ paymentRefId, expectedAmount, expectedOrderId? }) Verify with Nagad, check the signature, compare amount and order, record the result.
nagad.payment.getStatus(paymentRefId) Raw status lookup. Not signature-checked and not compared with your order. Do not fulfil on it. Use verify.
nagad.reconcile(paymentRefId) Re-verify a stored session that was interrupted; returns null if it cannot be confirmed.
nagad.init() Runs the crypto capability check at startup.
nagad.raw.post(path, body) Escape hatch for calls the SDK does not wrap. Unsigned; you own correctness.

Refund and webhook are not implemented.

#create

const { callBackUrl, paymentReferenceId, orderId } = await nagad.checkout.create({
  amount: '1250.00',        // string or integer poisha
  callbackUrl: 'https://shop.example/api/nagad/callback',
  orderId: undefined,       // optional; generated when omitted
  clientType: 'PC_WEB',     // PC_WEB | MOBILE_WEB | MOBILE_APP | WALLET_WEB_VIEW
});

#verify

verify throws NagadVerificationMismatchError if the amount, order id or merchant differ, NagadSignatureVerificationError if the response signature is wrong, NagadReplayAttackError for a replayed callback and NagadConcurrentVerificationError if another worker is verifying the same payment. A repeated verify of an already-verified payment returns the stored result without calling Nagad again.

#Session stores

The store remembers each order between create and verify, rejects duplicate order ids, and prevents double verification.

import Redis from 'ioredis';
import { RedisSessionStore } from 'nagad-server/redis';
const sessionStore = new RedisSessionStore({ redis: new Redis(process.env.REDIS_URL!) });

Also available: nagad-server/upstash (UpstashRestSessionStore) and nagad-server/kv (GenericKvSessionStore, for Cloudflare KV or Vercel KV style stores). The memory store is for development only.

#HTTP handler

import { createWebHandler } from 'nagad-server/frameworks';
const handle = createWebHandler(nagad, {
  basePath: '/api/nagad',
  resolveOrder: async (req, body) => ({ amount, orderId }),
  callbackUrl: 'https://shop.example/api/nagad/callback',
  allowedCallbackOrigins: ['https://shop.example'],
  resolveExpectedAmount: async ({ paymentRefId, orderId }) => amount, // optional
  onSuccess: async (result) => { await markPaid(result); },
});
Route Behaviour
POST /create Requires resolveOrder (or the unsafe allowClientAmount: true). amount, orderId, clientIp, clientType and TTL from the browser are ignored. A browser callbackUrl is used only if its origin is on allowedCallbackOrigins.
GET|POST /callback Verifies server-side. With no stored session and no resolveExpectedAmount it answers 404 unknown_session. The public response contains only success, orderId, paymentRefId, amount, status, statusCode, issuerPaymentDateTime.

Errors map to minimal responses: timeout → 202 unknown, session missing → 404, mismatch → 409, other SDK errors → 400 with code, anything else → 500 without internals.

#Framework adapters

import {
  createExpressMiddleware, createFastifyPlugin, createHonoHandler, createKoaMiddleware,
  createNestMiddleware, createNextRouteHandler, createNitroHandler, createRemixAction,
  createSvelteKitHandler, createAstroHandler,
} from 'nagad-server/frameworks';
// Next.js App Router: app/api/nagad/[...route]/route.ts
export const { GET, POST } = createNextRouteHandler(nagad, { basePath: '/api/nagad', resolveOrder });

Express, Next.js and Hono are exercised by tests; the others are thin wrappers and are marked experimental in the feature status.

Found a mistake? Edit this page on GitHub. Unofficial community project, not affiliated with Nagad or Third Wave Technologies Ltd.