File Upload Guide¶
Learn how to upload financial documents to Laminr for processing.
Overview¶
Files are uploaded to packages. A package is a container that groups related documents together (e.g., all documents for a single loan application).
Workflow:
- Create a package
- Upload one or more files to the package
- Monitor processing status
- Retrieve results
See the Getting Started guide for a complete walkthrough.
Supported File Types¶
Laminr accepts various financial document types:
- Bank statements: PDF, PNG, JPEG
- Pay stubs: PDF, PNG, JPEG
- Tax returns: PDF
- W-2 forms: PDF, PNG, JPEG
File requirements:
- Maximum file size: 1 GB per file
- Recommended: 300 DPI or higher for scanned documents
- PDF format preferred for best results
Best Quality
For best extraction accuracy, use high-quality PDFs generated directly from financial institutions rather than scanned documents.
Upload Files to a Package¶
File uploads use a three-step process with presigned URLs for secure, direct-to-storage uploads:
Step 1: Get a Presigned Upload URL¶
Endpoint:
Request:
curl -X POST https://api.laminr.ai/api/v1/files \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"file_name": "bank_statement.pdf"}'
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
file_name | string | Yes | The name of the file you want to upload |
Response:
{
"upload_url": "https://storage.example.com/presigned-url-with-credentials...",
"uri": "tenants/123/files/1699123456-789-bank-statement-pdf"
}
The upload_url is a temporary presigned URL that allows you to upload directly to cloud storage. The uri is the permanent identifier for the file that you'll use in Step 3.
Step 2: Upload File to Presigned URL¶
Upload your file directly to the presigned URL using HTTP PUT:
curl -X PUT "https://storage.example.com/presigned-url-with-credentials..." \
--upload-file /path/to/bank_statement.pdf \
-H "Content-Type: application/pdf"
Direct Upload
This upload goes directly to cloud storage (not through the Laminr API), which provides better performance and reliability for large files.
Step 3: Create File Record in Package¶
After uploading, create the file record in your package:
Endpoint:
Request:
curl -X POST https://api.laminr.ai/api/v1/packages/LP-2025-001/files \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"uri": "tenants/123/files/1699123456-789-bank-statement-pdf",
"file_name": "bank_statement.pdf"
}'
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
uri | string | Yes | The URI returned from Step 1 |
file_name | string | Yes | The name of the file |
Response:
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"loan_package_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"file_name": "bank_statement.pdf",
"file_extension": "pdf",
"file_size": 245678,
"file_md5_hash": "abc123def456...",
"file_content_type": "application/pdf",
"file_created_at": "2025-11-05T10:05:00.000000+00:00",
"status": "queued",
"created_at": "2025-11-05T10:05:00.000000+00:00",
"updated_at": "2025-11-05T10:05:00.000000+00:00",
"progress": null
}
Upload Multiple Files¶
You can upload multiple files to the same package. Each file is processed independently. Repeat the three-step process for each file:
# File 1
curl -X POST https://api.laminr.ai/api/v1/files \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"file_name": "bank_statement_jan.pdf"}'
# Returns upload_url and uri
curl -X PUT "<upload_url>" --upload-file bank_statement_jan.pdf
curl -X POST https://api.laminr.ai/api/v1/packages/LP-2025-001/files \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"uri": "<uri>", "file_name": "bank_statement_jan.pdf"}'
# File 2
curl -X POST https://api.laminr.ai/api/v1/files \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"file_name": "bank_statement_feb.pdf"}'
# Returns upload_url and uri
curl -X PUT "<upload_url>" --upload-file bank_statement_feb.pdf
curl -X POST https://api.laminr.ai/api/v1/packages/LP-2025-001/files \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"uri": "<uri>", "file_name": "bank_statement_feb.pdf"}'
Check Processing Status¶
After uploading, files go through several processing stages:
| Status | Description |
|---|---|
queued | File has been uploaded and is waiting to be processed |
processing | Document is being analyzed and data extracted |
processed | Processing finished successfully |
failed | Processing failed (see error details) |
Check Package Status¶
Get the overall status of all files in a package:
Response:
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"tenant": {
"id": "tenant_123",
"name": "Your Company"
},
"title": "John Doe Application",
"public_id": "LP-2025-001",
"created_at": "2025-11-05T10:00:00.000000+00:00",
"updated_at": "2025-11-05T10:05:30.000000+00:00",
"status": "Processing",
"created_by": {
"id": "user_123",
"email": "you@example.com"
},
"progress": 0.5,
"under_review": false
}
To see individual file statuses, list the files in the package:
The package status will be: - "Processing": Files are still being processed - "Processed": All files have been processed successfully - "Under Review": Package is under manual review
The progress field (0.0 to 1.0) indicates overall package processing progress.
Error Handling¶
Upload Errors¶
Common upload errors:
{
"error": {
"code": "invalid_file_type",
"message": "File type not supported. Accepted types: PDF, PNG, JPEG"
}
}
Common error codes: - invalid_file_type: Unsupported file format - file_too_large: File exceeds 10 MB limit - invalid_package: Package ID not found - rate_limit_exceeded: Too many requests
Processing Errors¶
If a file fails to process, check the package details for error information:
{
"id": "file_xyz789",
"filename": "bank_statement.pdf",
"status": "failed",
"error": {
"code": "extraction_failed",
"message": "Unable to extract data from document",
"details": "Document quality too low for reliable extraction"
}
}
Best Practices¶
File Quality¶
- Use PDF format when possible
- Ensure text is readable (not too blurry or low resolution)
- Avoid heavily compressed images
- For scans, use at least 300 DPI
Batch Uploads¶
Upload files concurrently to save time:
import asyncio
import aiohttp
async def upload_file(session, package_id, filepath, api_key):
headers = {'x-api-key': api_key}
# Step 1: Get presigned URL
async with session.post(
'https://api.laminr.ai/api/v1/files',
json={'file_name': filepath},
headers=headers
) as response:
data = await response.json()
upload_url = data['upload_url']
uri = data['uri']
# Step 2: Upload file to presigned URL
with open(filepath, 'rb') as f:
file_data = f.read()
async with session.put(upload_url, data=file_data) as response:
await response.read()
# Step 3: Create file record in package
async with session.post(
f'https://api.laminr.ai/api/v1/packages/{package_id}/files',
json={'uri': uri, 'file_name': filepath},
headers=headers
) as response:
return await response.json()
async def batch_upload(package_id, filepaths, api_key):
async with aiohttp.ClientSession() as session:
tasks = [upload_file(session, package_id, fp, api_key) for fp in filepaths]
return await asyncio.gather(*tasks)
# Upload 3 files concurrently
API_KEY = 'your_api_key_here'
files = ['statement1.pdf', 'statement2.pdf', 'paystub.pdf']
results = asyncio.run(batch_upload('LP-2025-001', files, API_KEY))
Monitoring Progress¶
Poll the package status endpoint to monitor processing:
import time
import requests
def wait_for_completion(package_id):
headers = {'x-api-key': API_KEY}
while True:
response = requests.get(
f'https://api.laminr.ai/api/v1/packages/{package_id}',
headers=headers
)
package = response.json()
if package['status'] == 'Processed':
print("Processing complete!")
return package
elif package['status'] == 'Failed':
print("Processing failed!")
return package
# Show progress (0.0 to 1.0)
progress = package['progress']
print(f"Progress: {progress * 100:.0f}%")
time.sleep(5) # Wait 5 seconds before checking again
result = wait_for_completion('LP-2025-001')
Supported Document Types¶
Bank Statements¶
- Extract transactions, balances, account information
- Supports most major US banks
- Best results with statements covering 2-3 months
Pay Stubs¶
- Extract income, deductions, YTD totals
- Supports standard pay stub formats
- Include multiple pay periods for better accuracy
Tax Returns¶
- Extract income, deductions, and tax information
- Supports Form 1040 and common schedules
- W-2 forms can be uploaded separately
Next Steps¶
- Getting Started Guide - Complete workflow walkthrough
- Authentication - API key management
- API Reference - Complete endpoint documentation
Support¶
Need help? Contact us at support@laminr.ai