bankstract

TypeScript SDK

Parse statements with @logickoder/bankstract, the typed Node.js client.

A typed Node.js wrapper over the /v1 API. Server-side only: the API key is a secret, so never ship it to a browser.

npm install @logickoder/bankstract

Node 18+ (uses the global fetch). Ships ESM and CommonJS; types are bundled.

Quickstart

import { bankstract } from '@logickoder/bankstract'
import { readFile } from 'node:fs/promises'

const client = bankstract({ apiKey: process.env.BANKSTRACT_API_KEY! })

const pdf = await readFile('statement.pdf')
const result = await client.parse(pdf)

console.log(result.metadata?.bank, result.transactions.length)

parse accepts Uint8Array | ArrayBuffer | Blob. See Authentication for keys and the parse endpoint for the response shape.

Redaction

const { data, format, redactions } = await client.redact(pdf, { bank: 'gtbank' })
// `data` is the redacted document bytes (PDF or XLSX), in memory.
await writeFile(`redacted.${format}`, data)

Usage and banks

const usage = await client.usage() // tier, parses this cycle, projected overage
const banks = await client.banks() // supported bank ids for the `bank` override

Options

bankstract({
  apiKey, // required
  baseUrl, // default 'https://bankstract.logickoder.dev'
  fetch, // inject a fetch implementation; default globalThis.fetch
  timeoutMs, // per-request timeout, default 30000
})

Per-call, parse and redact take { bank?, filename?, signal? }.

Errors

Every non-2xx response throws a typed BankstractError subclass. The API key never appears in the error. The thrown error mirrors the error envelope: status, errorClass, and markerCoverage where relevant.

import { RateLimitError, UnsupportedStatementError, BankstractError } from '@logickoder/bankstract'

try {
  await client.parse(pdf)
} catch (err) {
  if (err instanceof RateLimitError) {
    console.log('retry after', err.retryAfter, 'seconds')
  } else if (err instanceof UnsupportedStatementError) {
    console.log('no parser matched:', err.errorClass, err.markerCoverage)
  } else if (err instanceof BankstractError) {
    console.log(err.status, err.errorClass, err.message)
  }
}
ThrowsWhen
AuthError401, missing or invalid key
SubscriptionInactiveError402, subscription inactive
PayloadTooLargeError413, file over 50MB
UnsupportedStatementError422, no parser, layout drift, or reconciliation (see errorClass, markerCoverage)
RateLimitError429, with retryAfter. The API no longer emits 429 (over-cap returns a 200 canned sample); kept as a defensive mapping.
ServerError5xx
TimeoutErrorrequest aborted (timeout or your signal)

On this page