Integrate bank‑statement parsing directly into your product with a simple, secure API. Retrieve results as OFX (default), ready to import into Quicken, MS Money, and accounting software, or as CSV.
Authenticate every request with an API token created in your dashboard.
Create a personal API token, then include it in the Authorization header on each call:
Authorization: Bearer YOUR_API_TOKEN
To create an API token:
Core endpoints for upload, extraction, and results
/api/documents/upload
Upload a statement file to begin processing.
Content-Type: multipart/form-data
{
"document": [file] // Required: The document file to upload
}
{
"success": true,
"message": "File uploaded successfully",
"data": {
"file_id": 1234,
"name": "statement.pdf"
}
}
/api/documents/extract
Start extraction for a previously uploaded file.
Content-Type: application/json
{
"file_id": 1234, // Required: ID of the uploaded file
"document_type_id": 5678 // Optional: ID of the document template to use
}
{
"success": true,
"message": "Extraction initialized successfully",
"data": {
"extraction_id": 9876,
"extraction_hash": "abc123-def456-ghi789-jkl012"
}
}
/api/documents/extraction/{hash}
Fetch the parsed results for a given extraction hash.
{hash}: The extraction hash returned by the extract endpoint
{
"success": true,
"data": {
"extraction_id": 9876,
"extraction_hash": "abc123-def456-ghi789-jkl012",
"file": {
"id": 1234,
"name": "statement.pdf"
},
"document_type": {
"id": 5678,
"name": "Bank Statement Template"
},
"fields": [
{
"field_id": 101,
"content": "Account Number",
"value": "1234567890",
"is_table": false,
"page": 1
},
{
"field_id": 102,
"content": "Statement Date",
"value": "2023-05-15",
"is_table": false,
"page": 1
},
{
"field_id": 103,
"content": "Balance",
"value": "$12,450.00",
"is_table": false,
"page": 1
},
{
"field_id": 104,
"content": "Transactions",
"is_table": true,
"page": 1,
"rows": [
{
"cells": [
{"value": "2023-05-10", "is_header": false},
{"value": "DEPOSIT", "is_header": false},
{"value": "$500.00", "is_header": false}
]
},
{
"cells": [
{"value": "2023-05-12", "is_header": false},
{"value": "WITHDRAWAL", "is_header": false},
{"value": "-$250.00", "is_header": false}
]
}
]
}
]
}
}
/api/documents/types
Retrieve a list of available document templates.
{
"success": true,
"data": [
{
"id": 5678,
"name": "Bank Statement Template",
"description": "Template for processing bank statement documents",
"is_public": true,
"fields_count": 10
},
{
"id": 5679,
"name": "Credit Card Statement Template",
"description": "Template for processing credit card statements",
"is_public": false,
"fields_count": 8
}
]
}
Copy‑paste snippets to integrate bank statement processing in minutes
# Upload document
curl -X POST https://ofxstatement.com/api/documents/upload \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "document=@/path/to/document.pdf"
# Extract data
curl -X POST https://ofxstatement.com/api/documents/extract \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"file_id": 1234, "document_type_id": 5678}'
# Get results
curl -X GET https://ofxstatement.com/api/documents/extraction/abc123-def456-ghi789-jkl012 \
-H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$apiToken = 'YOUR_API_TOKEN';
$apiBaseUrl = 'https://ofxstatement.com/api';
// 1. Upload document
$filePath = '/path/to/document.pdf';
$ch = curl_init("$apiBaseUrl/documents/upload");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $apiToken"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'document' => new CURLFile($filePath)
]);
$uploadResponse = curl_exec($ch);
curl_close($ch);
$uploadResult = json_decode($uploadResponse, true);
if (!$uploadResult['success']) {
die('Error uploading document: ' . $uploadResult['message']);
}
$fileId = $uploadResult['data']['file_id'];
echo "File uploaded with ID: $fileId\n";
// 2. Extract data
$ch = curl_init("$apiBaseUrl/documents/extract");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $apiToken",
"Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'file_id' => $fileId,
'document_type_id' => 5678 // Optional
]));
$extractResponse = curl_exec($ch);
curl_close($ch);
$extractResult = json_decode($extractResponse, true);
if (!$extractResult['success']) {
die('Error extracting data: ' . $extractResult['message']);
}
$extractionHash = $extractResult['data']['extraction_hash'];
echo "Extraction initialized with hash: $extractionHash\n";
// 3. Get extraction results
$ch = curl_init("$apiBaseUrl/documents/extraction/$extractionHash");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $apiToken"
]);
$resultsResponse = curl_exec($ch);
curl_close($ch);
$resultsData = json_decode($resultsResponse, true);
if (!$resultsData['success']) {
die('Error getting extraction results: ' . $resultsData['message']);
}
// Process the extracted data
$fields = $resultsData['data']['fields'];
foreach ($fields as $field) {
echo $field['content'] . ': ' . $field['value'] . "\n";
}
// Complete document processing with JavaScript
const apiToken = 'YOUR_API_TOKEN';
const apiBaseUrl = 'https://ofxstatement.com/api';
// 1. Upload document
async function uploadDocument(filePath) {
const formData = new FormData();
formData.append('document', document.querySelector('input[type="file"]').files[0]);
const response = await fetch(`${apiBaseUrl}/documents/upload`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiToken}`
},
body: formData
});
const result = await response.json();
if (!result.success) {
throw new Error(`Error uploading document: ${result.message}`);
}
console.log(`File uploaded with ID: ${result.data.file_id}`);
return result.data.file_id;
}
// 2. Extract data
async function extractData(fileId, documentTypeId = null) {
const payload = {
file_id: fileId
};
if (documentTypeId) {
payload.document_type_id = documentTypeId;
}
const response = await fetch(`${apiBaseUrl}/documents/extract`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const result = await response.json();
if (!result.success) {
throw new Error(`Error extracting data: ${result.message}`);
}
console.log(`Extraction initialized with hash: ${result.data.extraction_hash}`);
return result.data.extraction_hash;
}
// 3. Get extraction results
async function getExtractionResults(extractionHash) {
const response = await fetch(`${apiBaseUrl}/documents/extraction/${extractionHash}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${apiToken}`
}
});
const result = await response.json();
if (!result.success) {
throw new Error(`Error getting extraction results: ${result.message}`);
}
console.log('Extraction results:', result.data);
// Process the extracted data
const fields = result.data.fields;
fields.forEach(field => {
console.log(`${field.content}: ${field.value}`);
});
return result.data;
}
// Usage
async function processDocument() {
try {
const fileId = await uploadDocument();
const extractionHash = await extractData(fileId, 5678); // Optional document type ID
const extractionData = await getExtractionResults(extractionHash);
// Do something with the extracted data
displayResults(extractionData);
} catch (error) {
console.error(error);
}
}
function displayResults(data) {
// Display the results in your application
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '';
data.fields.forEach(field => {
const fieldEl = document.createElement('div');
fieldEl.classList.add('field');
fieldEl.innerHTML = `${field.content}: ${field.value}`;
resultsDiv.appendChild(fieldEl);
});
}
import requests
import json
import time
api_token = 'YOUR_API_TOKEN'
api_base_url = 'https://ofxstatement.com/api'
# 1. Upload document
def upload_document(file_path):
headers = {
'Authorization': f'Bearer {api_token}'
}
with open(file_path, 'rb') as file:
files = {'document': file}
response = requests.post(
f'{api_base_url}/documents/upload',
headers=headers,
files=files
)
result = response.json()
if not result.get('success'):
raise Exception(f"Error uploading document: {result.get('message')}")
file_id = result['data']['file_id']
print(f"File uploaded with ID: {file_id}")
return file_id
# 2. Extract data
def extract_data(file_id, document_type_id=None):
headers = {
'Authorization': f'Bearer {api_token}',
'Content-Type': 'application/json'
}
payload = {
'file_id': file_id
}
if document_type_id:
payload['document_type_id'] = document_type_id
response = requests.post(
f'{api_base_url}/documents/extract',
headers=headers,
data=json.dumps(payload)
)
result = response.json()
if not result.get('success'):
raise Exception(f"Error extracting data: {result.get('message')}")
extraction_hash = result['data']['extraction_hash']
print(f"Extraction initialized with hash: {extraction_hash}")
return extraction_hash
# 3. Get extraction results
def get_extraction_results(extraction_hash):
headers = {
'Authorization': f'Bearer {api_token}'
}
response = requests.get(
f'{api_base_url}/documents/extraction/{extraction_hash}',
headers=headers
)
result = response.json()
if not result.get('success'):
raise Exception(f"Error getting extraction results: {result.get('message')}")
print("Extraction results:")
fields = result['data']['fields']
for field in fields:
print(f"{field['content']}: {field['value']}")
return result['data']
# Usage
def process_document(file_path, document_type_id=None):
try:
# Upload document
file_id = upload_document(file_path)
# Extract data
extraction_hash = extract_data(file_id, document_type_id)
# Get results (you might need to wait for processing to complete)
time.sleep(2) # Simple delay to wait for processing
extraction_data = get_extraction_results(extraction_hash)
# Process the extracted data further if needed
return extraction_data
except Exception as e:
print(f"Error: {str(e)}")
return None
# Process bank statement
if __name__ == "__main__":
result = process_document('/path/to/statement.pdf', 5678) # Optional document type ID
print(json.dumps(result, indent=2))
Operational limits and how to get help
Rate limits for Pro plan:
Exceeding these limits returns HTTP 429 (Too Many Requests). Response headers indicate when you can retry.
If you have any questions or need assistance with our API, please contact us:
Get started converting bank statements to OFX.
USD
per month
billed as
$288 yearly
Choose speed vs accuracy when extracting
| Base AI Faster | 2,500 pages |
| Pro AI Best accuracy | 500 pages |
Scale statement conversion across your team with automation.
USD
per month
billed as
$888 yearly
Choose speed vs accuracy when extracting
| Base AI Faster | 10,000 pages |
| Pro AI Best accuracy | 2,000 pages |
Enterprise-grade bank statement conversion and controls.
USD
per month
billed as
$ yearly
Choose speed vs accuracy when extracting
| Base AI Faster | pages |
| Pro AI Best accuracy | pages |