API Reference

Complete type reference for @localpay/verification-engine.

VerifyPayload fields

FieldTypeRequiredDescription
bankstringyesParser key — e.g. CBE, TELEBIRR, ABYSSINIA, EBIRR
amountnumberyesExpected transfer amount
verMethodVerificationMethodyesLINK | SMS | TRANSACTION_REF | OCR | SCREENSHOT
rawProofstring | BufferyesURL, SMS text, transaction ref, file path, or Buffer
accountNumberstringnoSender account number — required for CBE 12-char refs
countryCodestringnoISO country code for proxy routing. Default: ET
amountTolerancenumbernoMax allowed difference between payload and receipt amount. Default: 0.01

RawReceipt fields

FieldTypeDescription
transactionNumberstringBank-issued transaction or reference ID
datestringRaw date string as returned by the bank. Use safeParsDate() to convert to Date.
amountstringAmount string as returned by the bank — may include currency symbol. Stripped automatically during amount comparison.
receiverAccountstringReceiving account number (may be masked, e.g. ****1234)
receiverNamestringAccount holder name of the receiving account

VerificationEngine options

OptionTypeDescription
proxyResolverProxyResolver | nullPer-country proxy config provider. Implement resolve(countryCode) to return ProxyConfig or null.
ocrReader(input: RawProof) => Promise<string>Custom OCR function. If not provided, tesseract.js is used internally.
parsersParserRegistryOverride or extend the parser registry. Spread PARSER_REGISTRY to keep built-in banks.
urlValidatorsRecord<string, UrlValidationConfig>Override or extend URL validators per bank. Spread URL_VALIDATION_REGISTRY to keep built-in validators.

Types & Interfaces

VerifyPayload

interface

Input to engine.verify(). All fields except bank, amount, verMethod, and rawProof are optional.

interface VerifyPayload { bank: string; amount: number; verMethod: VerificationMethod; rawProof: RawProof; // string | Buffer accountNumber?: string; // CBE 12-char refs — sender account suffix countryCode?: string; // Default: "ET" amountTolerance?: number; // Default: 0.01 }

VerifyResult

type

Discriminated union returned by engine.verify(). Narrow on status to access the correct fields.

type VerifyResult = | { status: "SUCCESS"; receipt: { bank: string; receipt: RawReceipt } } | { status: "FAIL"; reason: string }

RawReceipt

interface

Structured receipt data returned by every parser. All fields are strings — amounts may include currency symbols, dates are raw bank strings.

interface RawReceipt { transactionNumber: string; date: string; // use safeParsDate() to convert to Date amount: string; // may include currency symbol e.g. "ETB 500.00" receiverAccount: string; receiverName: string; }

VerificationMethod

type

All supported verification methods. SCREENSHOT is an alias for OCR — they behave identically.

type VerificationMethod = | "LINK" // receipt URL passed directly | "SMS" // raw SMS body — parser extracts the link | "TRANSACTION_REF" // transaction or reference number — parser builds the URL | "OCR" // image path or Buffer — OCR runs internally | "SCREENSHOT" // alias of OCR

VerificationEngineOptions

interface

Constructor options for VerificationEngine. All fields are optional.

interface VerificationEngineOptions { proxyResolver?: ProxyResolver | null; ocrReader?: (input: RawProof) => Promise<string>; parsers?: ParserRegistry; urlValidators?: Record<string, UrlValidationConfig>; }

UrlValidationConfig

interface

Per-bank URL validation config. domains is the list of allowed hostnames. validate() is called with the parsed URL and should throw on invalid structure.

interface UrlValidationConfig { domains: string[]; validate(parsed: URL): void; } // Built-in registry — import and spread when adding custom banks import { URL_VALIDATION_REGISTRY } from "@localpay/verification-engine"; const engine = new VerificationEngine({ urlValidators: { ...URL_VALIDATION_REGISTRY, MY_BANK: { domains: ["receipts.my-bank.et"], validate(parsed) { if (!parsed.searchParams.get("ref")) { throw new Error("Missing receipt reference."); } }, }, }, });

ParserAndExtractor

interface

Contract every bank parser must implement. extract(), fetch(), and receiptParser() are required. transactionRef() is optional — used when verMethod is TRANSACTION_REF.

interface ParserAndExtractor { extract( text: string, accountNumber?: string, ): { link: string }; transactionRef?( ref: string, accountNumber?: string, ): { link: string }; fetch( link: string, context?: ParserFetchContext, ): Promise<{ page: any }>; receiptParser( page: any, ): Promise<{ bank: string; receipt: RawReceipt }>; }

ParserFetchContext

interface

Passed to fetch() so parsers can route through the engine's BankFetchService (including proxy). Always use context.fetcher instead of raw axios or fetch() inside parsers.

interface ParserFetchContext { fetcher: BankFetchService; countryCode: string; }

ProxyResolver

interface

Implement this in your host app to provide per-country proxy config from your database, config store, or environment. Return null to make the request without a proxy.

interface ProxyResolver { resolve(countryCode: string): Promise<ProxyConfig | null>; } // Example with Prisma const proxyResolver: ProxyResolver = { resolve: async (countryCode) => { const row = await prisma.countryProxy.findUnique({ where: { countryCode } }); if (!row?.proxyEnabled) return null; return { enabled: true, url: row.proxyUrl, type: row.proxyType as ProxyType }; }, };

ProxyConfig

interface

Proxy configuration returned by ProxyResolver.resolve(). url must be a full proxy URL including credentials.

interface ProxyConfig { enabled: boolean; url: string | null; // e.g. "http://user:pass@proxy.host:8080" type: ProxyType; } enum ProxyType { HTTP_CONNECT = "HTTP_CONNECT", // default — works for most banks SOCKS5 = "SOCKS5", // use when bank does deep packet inspection }

BankFetchService

class

The single HTTP gateway used by all parsers. Handles proxy routing, retries, and timeouts. Pass context.fetcher inside parser fetch() methods to get proxy support automatically.

const fetcher = new BankFetchService( proxyResolver?: ProxyResolver | null, ); const result = await fetcher.fetch( url: string, countryCode: string, options?: BankFetchOptions, ): Promise<{ data: any }>; interface BankFetchOptions { responseType?: "arraybuffer" | "json" | "text"; headers?: Record<string, string>; timeoutMs?: number; // default: 10000 }

FetchError

class

Thrown by BankFetchService when all retry attempts are exhausted.

class FetchError extends Error { url: string; countryCode: string; cause: unknown; }

PARSER_REGISTRY

const

Default parser registry containing all built-in bank parsers. Extend by spreading into a new object and passing via the parsers constructor option.

import { PARSER_REGISTRY, VerificationEngine } from "@localpay/verification-engine"; // Inspect supported banks console.log(Object.keys(PARSER_REGISTRY)); // → ["CBE", "TELEBIRR", "ABYSSINIA", "EBIRR"] // Extend with your own parser const engine = new VerificationEngine({ parsers: { ...PARSER_REGISTRY, MY_BANK: new MyBankParser(), }, });

URL_VALIDATION_REGISTRY

const

Default URL validation configs for all built-in banks. Each entry defines allowed domains and a structural validate() function. Spread when adding custom bank validators.

import { URL_VALIDATION_REGISTRY } from "@localpay/verification-engine"; console.log(Object.keys(URL_VALIDATION_REGISTRY)); // → ["CBE", "TELEBIRR", "ABYSSINIA", "EBIRR"] // Each config has: // { // domains: string[] — allowed hostnames // validate: (parsed: URL) => void — structural check, throws on invalid URL // }

safeParsDate

function

Parse a raw bank date string into a Date object. Returns null instead of throwing on unrecognised formats — safe to use directly on receipt data.

import { safeParsDate } from "@localpay/verification-engine"; safeParsDate("18-03-2026 21:46:09"); // → Date (Telebirr format) safeParsDate("2026-02-11 20:07:02 +0300 EAT"); // → Date (eBirr format) safeParsDate("3/11/2026, 6:15:00 PM"); // → Date (CBE PDF format) safeParsDate("23/01/26 14:04"); // → Date (BOA format) safeParsDate("not a date"); // → null (never throws) safeParsDate(null); // → null

parseDate

function

Same as safeParsDate but throws on unrecognised formats instead of returning null. Use when you want strict parsing.

import { parseDate } from "@localpay/verification-engine"; parseDate("18-03-2026 21:46:09"); // → Date parseDate("not a date"); // → throws Error: Unsupported date format