API Reference
Complete type reference for @localpay/verification-engine.
VerifyPayload fields
| Field | Type | Required | Description |
|---|---|---|---|
| bank | string | yes | Parser key — e.g. CBE, TELEBIRR, ABYSSINIA, EBIRR |
| amount | number | yes | Expected transfer amount |
| verMethod | VerificationMethod | yes | LINK | SMS | TRANSACTION_REF | OCR | SCREENSHOT |
| rawProof | string | Buffer | yes | URL, SMS text, transaction ref, file path, or Buffer |
| accountNumber | string | no | Sender account number — required for CBE 12-char refs |
| countryCode | string | no | ISO country code for proxy routing. Default: ET |
| amountTolerance | number | no | Max allowed difference between payload and receipt amount. Default: 0.01 |
RawReceipt fields
| Field | Type | Description |
|---|---|---|
| transactionNumber | string | Bank-issued transaction or reference ID |
| date | string | Raw date string as returned by the bank. Use safeParsDate() to convert to Date. |
| amount | string | Amount string as returned by the bank — may include currency symbol. Stripped automatically during amount comparison. |
| receiverAccount | string | Receiving account number (may be masked, e.g. ****1234) |
| receiverName | string | Account holder name of the receiving account |
VerificationEngine options
| Option | Type | Description |
|---|---|---|
| proxyResolver | ProxyResolver | null | Per-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. |
| parsers | ParserRegistry | Override or extend the parser registry. Spread PARSER_REGISTRY to keep built-in banks. |
| urlValidators | Record<string, UrlValidationConfig> | Override or extend URL validators per bank. Spread URL_VALIDATION_REGISTRY to keep built-in validators. |
Types & Interfaces
VerifyPayload
interfaceInput 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
typeDiscriminated 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
interfaceStructured 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
typeAll 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 OCRVerificationEngineOptions
interfaceConstructor options for VerificationEngine. All fields are optional.
interface VerificationEngineOptions {
proxyResolver?: ProxyResolver | null;
ocrReader?: (input: RawProof) => Promise<string>;
parsers?: ParserRegistry;
urlValidators?: Record<string, UrlValidationConfig>;
}UrlValidationConfig
interfacePer-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
interfaceContract 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
interfacePassed 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
interfaceImplement 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
interfaceProxy 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
classThe 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
classThrown by BankFetchService when all retry attempts are exhausted.
class FetchError extends Error {
url: string;
countryCode: string;
cause: unknown;
}PARSER_REGISTRY
constDefault 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
constDefault 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
functionParse 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); // → nullparseDate
functionSame 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