Files API
The Files API is the core of Excellent Banking. It handles the full lifecycle of a bank statement:
- Upload — Get a pre-signed MinIO URL, push your file directly to storage
- Process — Trigger AI-powered transaction extraction (consumes credits)
- Download — Retrieve the processed Excel or original PDF
All endpoints require Clerk JWT authentication.
File Status Lifecycle
Section titled “File Status Lifecycle”pending → processing → completed ↘ errorpending— File uploaded but not yet processedprocessing— AI extraction in progresscompleted— Extraction done, Excel available for downloaderror— Processing failed (seeprocessed_datafor details)
Upload a File
Section titled “Upload a File”POST
/files/upload-url
Generates a pre-signed PUT URL for direct upload to MinIO (our S3-compatible storage). Your browser uploads the file directly — it never passes through our API server. A File record is created in pending status.
Request body:
{ "filename": "statement-january-2026.pdf", "file_size": 1048576, "mime_type": "application/pdf"}| Field | Type | Required | Description |
|---|---|---|---|
filename | string | Yes | Display name for the file |
file_size | integer | No | Size in bytes (informational) |
mime_type | string | No | Defaults to application/pdf |
Response (200):
{ "upload_url": "https://minio.example.com/uploads/user_id=42/file_id=128/abc-123.pdf?X-Amz-...", "file_id": 128, "storage_path": "uploads/user_id=42/file_id=128/abc-123.pdf"}Upload flow after getting the URL:
curl -X PUT "https://minio.example.com/uploads/..." \ --upload-file statement.pdfAfter the upload completes, the file is stored and ready for processing.
List Files
Section titled “List Files”GET
/files/
Returns all files owned by the authenticated user, ordered by newest first.
Query parameters:
| Param | Type | Default | Description |
|---|---|---|---|
skip | integer | 0 | Offset for pagination |
limit | integer | 20 | Max results per page (≤100) |
status | string | — | Filter by status: pending, processing, completed, error |
Example:
curl -H "Authorization: Bearer TOKEN" \ "https://api.excellent-banking.com/files/?status=completed&limit=5"Response (200):
[ { "id": 128, "filename": "statement-january-2026.pdf", "original_filename": "statement-january-2026.pdf", "file_size": 1048576, "mime_type": "application/pdf", "storage_path": "uploads/user_id=42/file_id=128/abc-123.pdf", "status": "completed", "description": null, "processed_data": { "transactions": [ {"date": "2026-01-15", "description": "Supermarkt", "amount": -45.20, "category": "Food"}, {"date": "2026-01-16", "description": "Gehalt", "amount": 3200.00, "category": "Income"} ], "total_pages": 3, "total_characters": 4500 }, "user_id": 42, "created_at": "2026-05-09T10:30:00Z", "updated_at": "2026-05-09T10:32:00Z" }]Get File Details
Section titled “Get File Details”GET
/files/{file_id}
Returns full details for a single file, including processed_data when the status is completed.
curl -H "Authorization: Bearer TOKEN" \ https://api.excellent-banking.com/files/128Response (200): Same shape as a single item from the list endpoint.
Errors:
| Status | When |
|---|---|
404 | File not found or doesn’t belong to the authenticated user |
Update File Metadata
Section titled “Update File Metadata”PATCH
/files/{file_id}
Update display metadata. Only the authenticated owner can modify the file.
Request body:
{ "filename": "Q1 Statement - January", "description": "N26 checking account statement"}Both fields are optional — only send what you want to change.
Response (200): The updated FileResponse object.
Delete a File
Section titled “Delete a File”DELETE
/files/{file_id}
Permanently deletes the file record and its associated MinIO objects. If the file was part of any dashboards, those dashboards are marked outdated.
curl -X DELETE -H "Authorization: Bearer TOKEN" \ https://api.excellent-banking.com/files/128Response (200):
{ "message": "File deleted successfully"}Check Processing Status
Section titled “Check Processing Status”GET
/files/{file_id}/status
Lightweight endpoint to poll processing progress without fetching the full file object.
Response (200):
{ "file_id": 128, "status": "processing", "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}Trigger Processing
Section titled “Trigger Processing”POST
/files/{file_id}/process
Starts the AI extraction pipeline. This is the action that consumes credits (minimum 1 credit per file).
Pre-conditions:
- File must belong to the authenticated user
- User must have at least 1 credit in their balance
Response (200):
{ "message": "Processing started", "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}The task_id can be correlated with the task_id returned by the status endpoint.
Errors:
| Status | Response | When |
|---|---|---|
402 | {"error": "insufficient_credits", "message": "You need at least 1 credit...", "balance": 0} | Credit balance < 1 |
404 | {"detail": "File not found"} | File doesn’t exist or doesn’t belong to user |
Download Processed Excel
Section titled “Download Processed Excel”GET
/files/{file_id}/download-excel-url
Returns a pre-signed GET URL for the processed Excel file. The URL is time-limited and can be used directly in a browser or curl.
curl -H "Authorization: Bearer TOKEN" \ https://api.excellent-banking.com/files/128/download-excel-urlResponse (200):
{ "download_url": "https://minio.example.com/excel/uploads/user_id=42/...xlsx?X-Amz-..."}The download filename is derived from the original filename, sanitized with underscores replacing special characters. For example, statement-january-2026.pdf becomes statement_january_2026.xlsx.
Download Original File
Section titled “Download Original File”GET
/files/{file_id}/download-raw-url
Returns a pre-signed GET URL for the original uploaded file (typically the PDF).
curl -H "Authorization: Bearer TOKEN" \ https://api.excellent-banking.com/files/128/download-raw-urlResponse (200):
{ "download_url": "https://minio.example.com/raw/uploads/user_id=42/...pdf?X-Amz-..."}