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-server

Or 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:

bash
Authorization: Bearer $YOUR_API_KEY
The token grants the same access as the owning account. Treat it as a password — store it in a secret manager, never commit it. Revoke it from the dashboard if you suspect it's been exposed.

Rate 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-data with a file field, or raw application/pdf body
Max body
25 MB / 100 pages
bash
curl -X POST https://www.statementedge.com/v1/convert \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -F file=@statement.pdf

Response — 202 Accepted

json
{
  "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.

bash
curl https://www.statementedge.com/v1/jobs/a4125885-1d6d-40a4-806d-e16945aaa6a8 \
  -H "Authorization: Bearer $YOUR_API_KEY"

Response shape

json
{
  "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.

ts
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:

json
{ "error": "Human-readable description of what went wrong." }
HTTPMeaningCommon cause
400Bad RequestNot a PDF, missing fields, oversized body
401UnauthorizedMissing/invalid/revoked bearer token
404Not FoundJob id doesn't exist or isn't yours
413Payload Too LargeFile > 25 MB
429Rate LimitedExceeded plan limit — backoff per Retry-After
500Server ErrorPipeline 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.