REST API + MCP server
Bank Statement Converter API for AI Agents
One POST turns a PDF bank statement into normalized, verified transactions. Every number carries a page and line citation plus the verbatim statement text, so your agent can audit exactly what it imports.
Base URL https://capyparse.com/api/v1
# Start a conversion (1 credit per page)
curl -X POST https://capyparse.com/api/v1/conversions \
-H "Authorization: Bearer cpk_live_YOUR_KEY" \
-F "file=@statement.pdf"
# Poll until completed, then fetch the result
curl "https://capyparse.com/api/v1/conversions/{id}/result?format=markdown" \
-H "Authorization: Bearer cpk_live_YOUR_KEY"Quickstart
First conversion in four steps
Everything below is a real request against the live API. Replace cpk_live_YOUR_KEY with your key.
Create an API key
Generate a key in the dashboard under Settings, API keys. Keys are scoped to your team, start with cpk_live_, and go in the Authorization header of every request.
Authorization: Bearer cpk_live_YOUR_KEYStart a conversion
Upload a PDF, PNG, or JPG (up to 50 pages and 50MB). Prefer JSON? Send {"file_url": "https://…"} or {"file_base64": "…", "filename": "statement.pdf"} instead of multipart.
curl -X POST https://capyparse.com/api/v1/conversions \
-H "Authorization: Bearer cpk_live_YOUR_KEY" \
-F "file=@statement.pdf"{
"id": "7d9c1a2e-4b6f-4c1e-9a2d-3f8e5b7c0d41",
"filename": "statement.pdf",
"status": "queued",
"pages": 4,
"credits_required": 4,
"created_at": "2026-07-11T14:03:22"
}Conversion costs 1 credit per page. If your team does not have enough credits, the API returns 402 before anything is queued.
Poll until completed
Status moves from queued to processing to completed or failed, typically within 1 to 3 minutes. A completed conversion includes a summary for each account found on the statement, with its verification status.
curl https://capyparse.com/api/v1/conversions/7d9c1a2e-4b6f-4c1e-9a2d-3f8e5b7c0d41 \
-H "Authorization: Bearer cpk_live_YOUR_KEY"{
"id": "7d9c1a2e-4b6f-4c1e-9a2d-3f8e5b7c0d41",
"status": "completed",
"pages": 4,
"accounts": [
{
"index": 0,
"account_number": "****1042",
"account_type": "Checking",
"is_credit_card": false,
"transaction_count": 87,
"skipped_row_count": 1,
"verification_status": "passed"
}
],
"result_url": "/api/v1/conversions/7d9c1a2e-4b6f-4c1e-9a2d-3f8e5b7c0d41/result"
}Fetch the result
Pick a format with format=json|csv|markdown|jsonl, a provenance level with provenance=none|summary|full (full adds per-field citations and confidence), and a single account from a multi-account statement with account=N.
curl "https://capyparse.com/api/v1/conversions/7d9c1a2e-4b6f-4c1e-9a2d-3f8e5b7c0d41/result?format=json&provenance=summary" \
-H "Authorization: Bearer cpk_live_YOUR_KEY"All endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/me | Plan, team, and remaining credits. |
| POST | /api/v1/conversions | Start a conversion from a file upload, URL, or base64 payload. Returns 202. |
| GET | /api/v1/conversions | List conversions. Supports limit, offset, and status filters. |
| GET | /api/v1/conversions/{id} | Status plus per-account summaries and verification once completed. |
| GET | /api/v1/conversions/{id}/result | The result as json, csv, markdown, or jsonl, with optional provenance. |
MCP
Connect your agent over MCP
Claude, Cursor, and any MCP-compatible client can drive CapyParse directly. Use the hosted server for zero setup, or the local package when your agent should convert files straight from disk.
Hosted server
Streamable HTTP at https://capyparse.com/mcp with your API key in the Authorization header. One command in Claude Code:
claude mcp add --transport http capyparse https://capyparse.com/mcp \
--header "Authorization: Bearer cpk_live_YOUR_KEY"Local server
Runs over stdio via npx -y capyparse-mcp and can convert local files by path. For Claude Desktop or Cursor, add:
{
"mcpServers": {
"capyparse": {
"command": "npx",
"args": ["-y", "capyparse-mcp"],
"env": { "CAPYPARSE_API_KEY": "cpk_live_YOUR_KEY" }
}
}
}Both servers expose the same five tools
Response formats
Results your agent can audit
Not a raw text dump: transactions come back normalized, cited, and checked against what is printed on the statement.
Normalized transactions
ISO dates, signed amounts (deposits positive, withdrawals negative), a direction field, and the running balance whenever the statement prints one.
Page and line citations
Every transaction cites where it came from (like p3:L14) and carries the verbatim source text, so agents can quote the statement itself.
Verified per account
Balance reconciliation, net change, and completeness checks return a passed or review status. Unverifiable rows are listed with a reason, never silently dropped.
A transaction in format=json
{
"index": 0,
"date": "2026-03-02",
"description": "PAYROLL ACME INC",
"amount": 2400.0,
"direction": "deposit",
"balance": 6461.87,
"flags": [],
"provenance": {
"page": 1,
"region": "p1:L22",
"source_text": "03/02 PAYROLL ACME INC 2,400.00 6,461.87",
"grounding": "verified"
}
}Each account also carries its verification report
"verification": {
"status": "passed",
"checks": [
{ "label": "Balance Reconciliation", "status": "pass",
"expected": 5241.87, "actual": 5241.87, "difference": 0.0 },
{ "label": "Net Change Verification", "status": "pass" },
{ "label": "Transaction Completeness", "status": "pass" }
]
}format=markdown drops straight into an LLM context
## Checking ****1042
Beginning balance: 4,061.87
Ending balance: 5,241.87
Deposits: 2,400.00 (1) · Withdrawals: 1,220.00 (2)
Verification: **passed** (Balance Reconciliation: pass, Net Change Verification: pass)
| # | Date | Description | Amount | Balance | Source |
|---|------|-------------|-------:|--------:|--------|
| 1 | 2026-03-02 | PAYROLL ACME INC | 2,400.00 | 6,461.87 | p1:L22 ok |
| 2 | 2026-03-05 | UTILITIES AUTOPAY | -96.30 | 6,365.57 | p1:L23 ok |
| 3 | 2026-03-14 | CHECK #1042 | -1,123.70 | 5,241.87 | p2:L8 ok |csv returns one row per transaction with the same citation columns, and jsonl streams one JSON object per line for pipelines.
Account
Auth, credits, and limits
Authentication
Create and revoke keys at Settings, API keys. Keys are team-scoped: API conversions share your team's credit balance and show up in the team dashboard alongside in-app scans.
Credits
One credit converts one statement page, the same rate as in-app scans. Check your balance any time:
curl https://capyparse.com/api/v1/me \
-H "Authorization: Bearer cpk_live_YOUR_KEY"{
"team": { "id": "…", "name": "Acme Bookkeeping" },
"plan": "Starter",
"credits": {
"subscription_remaining": 118,
"flex": 25,
"total_available": 143,
"note": "One credit converts one statement page."
}
}Limits
Input files
PDF, PNG, or JPG
File size
Up to 50 pages and 50MB per file
Requests
120 per minute per API key
Conversion starts
30 per hour per API key
Errors
Predictable, machine-readable errors
Every error is JSON with a stable code your agent can branch on.
{
"detail": {
"code": "insufficient_credits",
"message": "This document needs 12 credits; 4 available."
}
}| Status | Code | What it means |
|---|---|---|
| 401 | missing_api_key, invalid_api_key, revoked_api_key | The Authorization header is missing, malformed, or the key was revoked. |
| 402 | insufficient_credits | Not enough credits for this document. Buy credits or upgrade, then retry. |
| 404 | not_found, account_not_found | The conversion id (or account index) does not exist on your team. |
| 409 | not_ready | The conversion is still queued or processing. Poll the status endpoint, then retry. |
| 413 | file_too_large | The file exceeds 50 pages or 50MB. Split the document and retry. |
| 422 | conversion_failed | The conversion failed, so no result is available. You were not charged. |
| 429 | rate_limited | Over 120 requests per minute or 30 conversion starts per hour. Back off and retry. |
Ship statement conversion this afternoon
Create a free account, generate a key under Settings, API keys, and your first conversion is one curl away.
1 credit per page · Free plan includes 10 pages
