Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nuban-cli

A command-line tool for batch validation of Nigerian bank account numbers (NUBAN). Reads accounts from a CSV file, queries the NUBAN API with bounded concurrency and per-request rate limiting, and writes the results to an Excel workbook with per-row status and a summary sheet.

Requirements

Installation

git clone <repo-url> nuban-cli
cd nuban-cli
npm install
cp .env.example .env
# Open .env and set NUBAN_API_KEY to your key.

Usage

Basic run (uses defaults from .env):

node src/cli.js --input accounts.csv

Custom output path:

node src/cli.js -i accounts.csv -o reports/may-2026.xlsx

Override concurrency for this run only:

node src/cli.js -i accounts.csv -c 10

Show stack traces on error (for debugging):

DEBUG=true node src/cli.js -i accounts.csv

Retry only the transient failures from a previous run, updating that file in place:

node src/cli.js --retry-from output.xlsx

This reads a previous run's output workbook and re-processes only the rows whose Status is API_ERROR with a transient Error reason (TIMEOUT, NETWORK_ERROR, RATE_LIMITED, API_BUSY). Rows that failed for a deterministic reason (NOT_FOUND, INVALID_ACCOUNT, UNKNOWN_ERROR) or that never reached the API (VALIDATION_ERROR) are skipped — retrying them would just reproduce the same result while burning through your rate-limit budget. Every other row (successes, deterministic failures) is carried over unchanged. --retry-from and -i/--input are mutually exclusive.

By default this overwrites output.xlsx in place — the retried rows are spliced back into their original positions and the file is rewritten whole. Pass -o to write the merged result somewhere else instead and leave the source file untouched:

node src/cli.js --retry-from output.xlsx -o retry.xlsx

Input CSV format

The first row must be headers. Header names are case-insensitive; the following variants are accepted:

Canonical field Accepted header variants
account_number account_number, account_no, acc_no, accountnumber
bank_code bank_code, bank_id, bankcode
provided_name provided_name, name, account_name, beneficiary_name (optional)

Per-row validation:

  • account_number — exactly 10 digits.
  • bank_code — exactly 3 or 6 digits.

Rows that fail validation are not aborted; they appear in the output with status = VALIDATION_ERROR.

If a provided_name column is present, each successfully resolved row is scored against the API's account_name using the same fuzzy name-matching logic as bankvalidatorinternal (src/name-matching.js) — see Name matching below. Rows without a provided_name value are not scored (Match Score = N/A); this is not treated as a mismatch.

Example:

account_number,bank_code,provided_name
0123456789,057,John Doe
1234567890,058,Jane Smith
2345678901,057,Ade Bello

Output Excel format

Sheet 1: Results

One row per input record, in original CSV order. Failed rows have a light-red background; the header is frozen.

Column Contents
Account Number from input
Bank Code from input
Provided Name from input (empty if no provided_name column)
Bank Name from API on success; empty on failure
Account Name from API on success; error reason on failure
Match Score 100/70/50/0 (as NN%) on success; N/A if no provided_name or on failure
Similarity Status reason text for the match score (e.g. Verified Match); N/A on failure
Status SUCCESS, API_ERROR, or VALIDATION_ERROR
Error error reason on failure; empty on success

API error reasons (appear in Error, and in Account Name for failed rows):

Reason Trigger
NOT_FOUND API returned no matching account.
INVALID_ACCOUNT API rejected the input as malformed.
TIMEOUT Request exceeded REQUEST_TIMEOUT_MS.
NETWORK_ERROR DNS / connection failure.
RATE_LIMITED API returned HTTP 429.
API_BUSY API returned a "try again" error body — its own transient failure, not the account/bank data.
UNKNOWN_ERROR Anything else (5xx, malformed response, etc.).

TIMEOUT, NETWORK_ERROR, and API_BUSY are retried automatically within a single run (RETRY_ATTEMPTS); API_BUSY and RATE_LIMITED are also what --retry-from looks for when re-running a previous output (see Usage).

VALIDATION_ERROR rows carry a human-readable validation message in Error (e.g. account_number must be exactly 10 digits).

Sheet 2: Summary

A two-column key/value table:

Metric Value
Total rows count
Succeeded count
Failed (API) count
Failed (Validation) count

Name matching

When a row has both a provided_name and a successful API account_name, the two are scored with the same fuzzy matcher bankvalidatorinternal uses (src/name-matching.js, ported from backend/utils/nameMatching.js so scoring stays identical between the two tools). It normalizes accents/case, strips filler words (ltd, mr, bank, …), and matches tokens by exact, initial, and typo-tolerant (Levenshtein ≥ 85%) comparison, then buckets the result:

Score Reason Meaning
100 Verified Match Every provided name token matched, same token count.
70 Partial Match (Verify) 2+ tokens matched, but not a perfect set.
50 High Risk (Incomplete) Exactly 1 token matched.
0 Mismatch (Rejected) No tokens matched.
0 N/A No provided_name was supplied for this row.

Configuration

Set these in .env. Only NUBAN_API_KEY is required.

Variable Default Purpose
NUBAN_API_KEY (required) Your NUBAN API key. The CLI exits with code 1 if missing.
CONCURRENCY_LIMIT 5 Max simultaneous in-flight API requests. Override with -c.
REQUESTS_PER_SECOND 0.25 Token-bucket refill rate. The default 0.25 matches the NUBAN free-tier limit of 15 req/min. Fractional values allowed.
REQUEST_TIMEOUT_MS 5000 Per-request timeout in milliseconds.
RETRY_ATTEMPTS 2 Retries per request after the first failure (only TIMEOUT / NETWORK_ERROR).
OUTPUT_FILE output.xlsx Default output path. Override with -o.

CONCURRENCY_LIMIT and REQUESTS_PER_SECOND are independent: concurrency caps how many requests can be in flight simultaneously, while the rate limiter caps long-run throughput. With the default 0.25 rps, throughput is the binding constraint regardless of concurrency — at startup the CLI prints an estimate so you know what to expect (e.g. Estimated time: ~67 min for 1000 rows at 15 req/min).

Troubleshooting

Error: NUBAN_API_KEY is not set. Copy .env.example to .env and fill in your key. You haven't created .env, or the key is blank. Run cp .env.example .env and populate NUBAN_API_KEY.

High failure rate (many TIMEOUT or RATE_LIMITED rows). The API is being asked for more than it can serve. Lower CONCURRENCY_LIMIT in .env, or pass -c 2 and raise gradually until failures stay under your tolerance.

Most or all requests time out. First, confirm the host is reachable: curl -I https://app.nuban.com.ng. If your network is reachable but slow, raise REQUEST_TIMEOUT_MS (e.g. to 15000). If you suspect a different bug, run with DEBUG=true to see the underlying stack trace.

Security

.env is .gitignored because it holds your NUBAN API key — that key authenticates billable API calls and grants access to account-lookup data.

  • Never commit .env, the raw key, or any log/screenshot containing the key. If a key leaks, rotate it immediately at https://app.nuban.com.ng.
  • The CLI loads the key into a non-enumerable property of the config object, so console.log(config) and JSON.stringify(config) cannot expose it.
  • The logger redacts any metadata field whose name contains key, token, secret, password, or authorization.
  • The HTTP client rewrites the API key out of any error URL or message before it reaches the logger.

These defenses reduce accidental leakage but do not substitute for keeping .env private.

About

A small, focused Node.js CLI for batch-validating Nigerian NUBAN account numbers from CSV input and producing a styled Excel report. It reads input rows, queries the NUBAN lookup API with concurrency + token-bucket rate limiting, applies a fuzzy name-matching scorer, and writes a results workbook with retry and summary features.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages