API
StatementEdge REST API
Convert PDF bank statements to clean, balance-reconciled data — programmatically. Self-serve, EU-hosted, 99% accuracy on digital PDFs.
Also available as an agent integration
Calling StatementEdge from Claude Desktop, Claude Code, or any MCP-aware client? Install the official server:
npx -y statementedge-mcp-serverOr browse the ClawHub agent skill for OpenClaw users. Both wrap the same REST API documented below — your API key (issued at Dashboard → API keys) works for all three surfaces and shares the same page allowance. Free plan can issue keys too — you get 7 pages/day for API and UI combined, no card required.
Overview
The API exposes the same conversion pipeline that powers the web app. You upload a PDF, get a job back, and poll until the conversion is done — usually 20–40 seconds end-to-end.
- Base URL
https://www.statementedge.com/v1- Auth
- Bearer token (below)
- Region
- EU (Frankfurt, fra1)
- Content
- application/json + multipart/form-data
- Rate limits
- 60 conversions / hour on Pro, 600 / hour on Business
- Availability
- Every plan (Free included) — API calls share the same page allowance as the UI
Authentication
Generate a key in the dashboard at Dashboard → API keys. Tokens look like se_live_… and are shown only once at creation. Free, Starter, Pro, and Business plans can all issue keys — your page allowance is the only metric that matters, regardless of whether the call came from a browser or an API client.
Pass the token as a Bearer in the Authorization header on every request:
Authorization: Bearer $YOUR_API_KEYRate limits
Limits are per API key. If you exceed them you get 429 Too Many Requests with a Retry-After header. Need higher limits? Contact sales — we offer custom volume on the Business plan.
POST /v1/convert
Upload a PDF and queue a conversion. Returns immediately with a job id and a status URL.
Request
- Endpoint
POST https://www.statementedge.com/v1/convert- Auth
- Required
- Content-Type
multipart/form-datawith afilefield, or rawapplication/pdfbody- Max body
- 25 MB / 100 pages
curl -X POST https://www.statementedge.com/v1/convert \
-H "Authorization: Bearer $YOUR_API_KEY" \
-F file=@statement.pdfResponse — 202 Accepted
{
"jobId": "a4125885-1d6d-40a4-806d-e16945aaa6a8",
"status": "queued",
"statusUrl": "https://www.statementedge.com/v1/jobs/a4125885-1d6d-40a4-806d-e16945aaa6a8"
}GET /v1/jobs/:id
Returns the current state of a job. When status reaches done, the response also contains the extracted statement and every transaction.
curl https://www.statementedge.com/v1/jobs/a4125885-1d6d-40a4-806d-e16945aaa6a8 \
-H "Authorization: Bearer $YOUR_API_KEY"Response shape
{
"job": {
"id": "a4125885-…",
"status": "done",
"original_filename": "statement.pdf",
"page_count": 1,
"error": null,
"created_at": "2026-06-01T17:32:01Z",
"completed_at": "2026-06-01T17:32:38Z"
},
"statement": {
"id": "a17fd3b8-…",
"bank_name": "Banco Synthetic EU",
"account_masked": "**** 1234",
"currency": "EUR",
"locale_number_format": "eu",
"opening_balance": 4280.50,
"closing_balance": 8318.48,
"period_start": "2026-05-01",
"period_end": "2026-05-31",
"reconcile_status": "reconciled",
"reconcile_notes": null
},
"transactions": [
{
"row_index": 0,
"date": "2026-05-01",
"description": "Apple iCloud",
"amount": -16.11,
"balance": 4264.39,
"raw_text": "01/05/2026 Apple iCloud -16,11 4.264,39",
"confidence": 1.0,
"flagged": false,
"flag_reason": null
}
]
}Polling pattern
Conversions typically complete in 20–60 seconds. Poll the status URL every 2–3 seconds with jittered backoff until job.status is done or failed. For long batches, raise the cap to ~5 minutes per file.
async function waitForCompletion(jobId: string, key: string, opts = { intervalMs: 2500, timeoutMs: 5 * 60_000 }) {
const deadline = Date.now() + opts.timeoutMs;
while (Date.now() < deadline) {
const r = await fetch(`https://www.statementedge.com/v1/jobs/${jobId}`, {
headers: { Authorization: `Bearer ${key}` },
});
const data = await r.json();
if (data.job.status === "done" || data.job.status === "failed") return data;
await new Promise((res) => setTimeout(res, opts.intervalMs));
}
throw new Error("timeout waiting for conversion");
}Errors
Errors follow a standard JSON envelope:
{ "error": "Human-readable description of what went wrong." }| HTTP | Meaning | Common cause |
|---|---|---|
| 400 | Bad Request | Not a PDF, missing fields, oversized body |
| 401 | Unauthorized | Missing/invalid/revoked bearer token |
| 404 | Not Found | Job id doesn't exist or isn't yours |
| 413 | Payload Too Large | File > 25 MB |
| 429 | Rate Limited | Exceeded plan limit — backoff per Retry-After |
| 500 | Server Error | Pipeline failure — retry safely |
Reconciliation statuses
reconcile_status on the statement object is one of three values. Use it to decide whether you can trust the output programmatically:
- reconciled — opening + Σ(amounts) = closing exactly, every per-row running balance is consistent, no parse failures. Safe to import without review.
- reconciled_with_flags — totals match, but at least one row is flagged (e.g. low model confidence, broken intermediate balance). Review only the flagged rows.
- needs_review — totals do not match. Treat the output as a draft; investigate before importing into accounting software.
File limits
- Max file size: 25 MB
- Max pages: 100 per file
- Concurrent jobs: 5 in-flight per key (Pro), 20 (Business)
- Source PDFs: auto-deleted from EU storage 1 hour after conversion (configurable)
Support
Hit a wall? Send us a message with your job id — if a statement didn't convert to your expectations, we'll dig in and fix the pipeline. Same human, EU-based, 24-hour SLA on Business.