Skip to content

Files API

The Files API is the core of Excellent Banking. It handles the full lifecycle of a bank statement:

  1. Upload — Get a pre-signed MinIO URL, push your file directly to storage
  2. Process — Trigger AI-powered transaction extraction (consumes credits)
  3. Download — Retrieve the processed Excel or original PDF

All endpoints require Clerk JWT authentication.

pending → processing → completed
↘ error
  • pending — File uploaded but not yet processed
  • processing — AI extraction in progress
  • completed — Extraction done, Excel available for download
  • error — Processing failed (see processed_data for details)

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"
}
FieldTypeRequiredDescription
filenamestringYesDisplay name for the file
file_sizeintegerNoSize in bytes (informational)
mime_typestringNoDefaults 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:

Terminal window
curl -X PUT "https://minio.example.com/uploads/..." \
--upload-file statement.pdf

After the upload completes, the file is stored and ready for processing.


GET /files/

Returns all files owned by the authenticated user, ordered by newest first.

Query parameters:

ParamTypeDefaultDescription
skipinteger0Offset for pagination
limitinteger20Max results per page (≤100)
statusstringFilter by status: pending, processing, completed, error

Example:

Terminal window
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 /files/{file_id}

Returns full details for a single file, including processed_data when the status is completed.

Terminal window
curl -H "Authorization: Bearer TOKEN" \
https://api.excellent-banking.com/files/128

Response (200): Same shape as a single item from the list endpoint.

Errors:

StatusWhen
404File not found or doesn’t belong to the authenticated user

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 /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.

Terminal window
curl -X DELETE -H "Authorization: Bearer TOKEN" \
https://api.excellent-banking.com/files/128

Response (200):

{
"message": "File deleted successfully"
}

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"
}

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:

StatusResponseWhen
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

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.

Terminal window
curl -H "Authorization: Bearer TOKEN" \
https://api.excellent-banking.com/files/128/download-excel-url

Response (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.


GET /files/{file_id}/download-raw-url

Returns a pre-signed GET URL for the original uploaded file (typically the PDF).

Terminal window
curl -H "Authorization: Bearer TOKEN" \
https://api.excellent-banking.com/files/128/download-raw-url

Response (200):

{
"download_url": "https://minio.example.com/raw/uploads/user_id=42/...pdf?X-Amz-..."
}