POST /v1/parse
Bank PDFs in.
Clean transactions out.
One API call. Structured transactions and balances back. If the totals don't match the statement, you get the reason. Never a wrong number.
Live: fbn, opay, palmpay, zenith
Sample parse. Synthetic data.
1,205.00
+250.00
Transfer FOO
bal 1,250.00
-40.00
POS ACME
-5.00
Airtime
Parse. Redact. Reconcile.
Built for lenders, bookkeeping tools and tax-prep apps. Anywhere a Nigerian bank statement has to become data.
Parse
Statement PDF in. Structured JSON out: transactions, balances, account metadata. One endpoint. One contract.
- Transfer FOO+250.00
- POS ACME-40.00
- Airtime-5.00
4
banks parse today
50 MB
max PDF size per upload
Redact
Names, account numbers and BVN masked in the same API. Get the redacted PDF back.
- Holder
- Redacted
- Account
- Redacted
- BVN
- Redacted
Reconcile
Balances and totals are checked on every parse. A mismatch returns an error with the reason, never a wrong number.
- opening
- 1,000.00
- + credits
- 250.00
- - debits
- 45.00
0
statement files written to disk
One call. curl, Python, TypeScript or Go. The same JSON back every time.
curl -X POST https://bankstract.logickoder.dev/v1/parse \
-H "Authorization: Bearer bsk_live_..." \
-F "pdf=@statement.pdf"import requests
with open("statement.pdf", "rb") as pdf:
res = requests.post(
"https://bankstract.logickoder.dev/v1/parse",
headers={"Authorization": "Bearer bsk_live_..."},
files={"pdf": pdf},
)
data = res.json()
print(data["metadata"]["bank"], len(data["transactions"]))const form = new FormData()
form.append("pdf", file)
const res = await fetch("https://bankstract.logickoder.dev/v1/parse", {
method: "POST",
headers: { Authorization: "Bearer bsk_live_..." },
body: form,
})
const data = await res.json()
console.log(data.metadata.bank, data.transactions.length)body := &bytes.Buffer{}
w := multipart.NewWriter(body)
part, _ := w.CreateFormFile("pdf", "statement.pdf")
io.Copy(part, file)
w.Close()
req, _ := http.NewRequest("POST", "https://bankstract.logickoder.dev/v1/parse", body)
req.Header.Set("Authorization", "Bearer bsk_live_...")
req.Header.Set("Content-Type", w.FormDataContentType())
res, _ := http.DefaultClient.Do(req)Fails loud.
A wrong number that looks right is the worst result. bankstract stops instead.
A parser that guesses
1,215.00
Reads one digit wrong. Returns a total anyway.
No error. No warning. It looks fine.
bankstract
- rows add up to
- 1,215.00
- statement says
- 1,205.00
- difference
- 10.00
Refused, with the reason.
HTTP status 422: the statement failed its checks.
- 422
Totals must match
Row balances are checked against the statement totals. If they do not add up, the API refuses the statement and says why.
- format_version
Layout drift gets a name
When a bank changes its statement layout, the error says which layout version failed. Rows never drop silently.
- 0 B
Nothing touches disk
PDF bytes stay in memory. No temp files. No disk writes. Dropped when the response ends.
Reads Naija banks first
4 banks parse today. 2 are next. 3 are planned. The roadmap is public. If a live bank changes its layout, the fix ships within 48h.
- livefbn
- liveopay
- livepalmpay
- livezenith
- gtbnext
- kudanext
- sparkleplanned
- alatplanned
- stanbicplanned
Compliance
NDPR by default.
Privacy is the product. Statements are parsed in memory and dropped. NDPR-aware redaction runs in the same API call. Every claim is verifiable in the open source.
01
In
The PDF arrives in the request and is held in memory.
02
Read
A child process reads it over a pipe. No temp file.
03
Out
Rows, or the redacted file, go back in the same response.
04
Dropped
The bytes are dropped when the response ends.
05
Logged
The audit log keeps filename and byte count. Never contents.
Read the security policy, check the source on GitHub, or run the MIT engine on your own infrastructure.
We're open source.
license
AGPL-3.0
The cloud layer and the engine are both public. Run the whole stack yourself. No license fee, no lock-in.
Call the API over HTTP and your code does not inherit AGPL. A hosted fork must open its changes.
The self-host bundle in infra/: the worker and a thin demo, on the engine. Star on GitHub.
Parse your first statement
Free demo, no signup. Self-host the whole stack, or use the cloud from ₦9,500/mo.
Prefer your own box? Self-host. Need volume or NDPR audit support? Talk to sales.