identitytutorialnigeria

Building a bank-transfer validation flow with MansaAPI (Node.js)

A complete Node.js tutorial: validate a NUBAN, resolve the bank code, and confirm the institution before sending a Nigerian bank transfer.

2026-05-29·9 min read

Before your app sends a Naira transfer, you want to catch errors early: a mistyped account number, a wrong bank selection, a non-existent institution. This tutorial builds a complete pre-transfer validation flow in Node.js using the MansaAPI identity suite.

What we're building

A reusable validateTransferDestination() function that:

flow
1. Checks the NUBAN checksum (free, instant)
2. Confirms the bank code maps to a real institution
3. Returns a clean result your payment code can branch on

Setup

terminal
npm install mansaapi
lib/mansa.ts
import { MansaAPI } from "mansaapi";

export const mansa = new MansaAPI({
  apiKey: process.env.MANSA_API_KEY!,
});

Step 1: NUBAN format check

The NUBAN checksum catches typos and bank/account mismatches before any paid lookup. It's free and instant.

validate.ts
import { mansa } from "./lib/mansa";

async function checkNubanFormat(account: string, bankCode: string) {
  const { data } = await mansa.identity.validateNuban(account, bankCode);
  return data.valid;
}

Step 2: Confirm the institution

validate.ts
import { MansaAPIError } from "mansaapi";

async function resolveBank(bankCode: string) {
  try {
    const { data: bank } = await mansa.identity.getBank(bankCode);
    return bank;
  } catch (err) {
    if (err instanceof MansaAPIError && err.status === 404) return null;
    throw err;
  }
}

Step 3: Combine into one function

validate.ts
export type TransferCheck =
  | { ok: true; bankName: string; bankCode: string; account: string }
  | { ok: false; reason: "invalid_format" | "unknown_bank" };

export async function validateTransferDestination(
  account: string,
  bankCode: string
): Promise<TransferCheck> {
  // 1. Format
  const formatOk = await checkNubanFormat(account, bankCode);
  if (!formatOk) return { ok: false, reason: "invalid_format" };

  // 2. Institution
  const bank = await resolveBank(bankCode);
  if (!bank) return { ok: false, reason: "unknown_bank" };

  return { ok: true, bankName: bank.name, bankCode, account };
}

Step 4: Use it in your transfer endpoint

route.ts (Next.js)
import { validateTransferDestination } from "@/validate";

export async function POST(req: Request) {
  const { account, bankCode, amount } = await req.json();

  const check = await validateTransferDestination(account, bankCode);
  if (!check.ok) {
    return Response.json({ error: check.reason }, { status: 400 });
  }

  // check.bankName is safe to show the user for confirmation
  // "Send ₦{amount} to {account} at {check.bankName}?"

  // ... proceed to your payment provider / name resolution ...
  return Response.json({ confirm: check.bankName });
}
The final step — confirming the account holder's name — requires a CBN-licensed provider (Paystack, NubAPI, etc.). Run this free validation first to cut the number of paid name lookups you make. See our guide on verifying Nigerian bank accounts.

Why validate before paying

Name-resolution calls cost money per lookup. Running the free NUBAN checksum and bank-code check first means you only pay for lookups that have a real chance of succeeding — typos and wrong-bank selections are rejected for free. On high volume, that's a meaningful saving.

Get a free key and start building — the identity suite (bank codes, NUBAN validation) is on the free tier.

Try it now

Free API key — 100 requests/day, no credit card.

Read docs