Integrate invoice data extraction directly into your product with a simple, secure API.
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:
Each token carries its own permissions, so a reporting script can read results without being able to upload, and an intake service can upload without reading anything else. A call outside the token's permissions returns HTTP 403. Uploads and result reads made with a token are recorded in your activity log under the token's name and role.
When you create a token you pick its role. Each role is a fixed set of permissions, and you can still adjust the permissions by hand, in which case the token shows as Custom.
| Role | Permissions | Typical use |
|---|---|---|
| Full access | upload-documents, extract-data, view-extractions, read | Uploads invoices, starts extractions and reads every result. For an integration that runs the whole flow. |
| Intake | upload-documents, extract-data, read | Uploads invoices and starts extractions. Cannot read extracted data. For a scanner, mailbox or upload service. |
| Read only | view-extractions, read | Reads extraction results. Cannot upload or start extractions. For reporting, BI and accounting sync. |
| Permission | Allows |
|---|---|
upload-documents | POST /api/documents/upload |
extract-data | POST /api/documents/extract (only files uploaded by your account) |
view-extractions | GET /api/documents/extraction/{hash} |
read | GET /api/documents/types |
Core endpoints for upload, extraction, and results
/api/documents/upload
Upload an invoice 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": "invoice.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": "invoice.pdf"
},
"document_type": {
"id": 5678,
"name": "Invoice 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": "Invoice Template",
"description": "Template for processing invoice documents",
"is_public": true,
"fields_count": 10
},
{
"id": 5679,
"name": "Purchase Order Template",
"description": "Template for processing purchase order documents",
"is_public": false,
"fields_count": 8
}
]
}
Get notified the moment an extraction finishes instead of polling.
Add an HTTPS endpoint in your dashboard under Webhooks and choose the events it receives. We send a POST with a JSON body when an extraction you started (in the dashboard or through the API) reaches its final state.
| Event | Sent when |
|---|---|
extraction.completed | All pages are processed. data.status is completed, or partial if some pages could not be read. |
extraction.failed | No page could be extracted, or the plan limit stopped the job. |
ping | You press Send test event. |
{
"id": "evt_8k2m4q9x1c7v5b3n6z0p2r4t",
"type": "extraction.completed",
"created": 1767225600,
"data": {
"extraction_id": 1234,
"extraction_hash": "abc123-def456-ghi789-jkl012",
"status": "completed",
"file": { "id": 5678, "name": "invoice-1042.pdf" },
"document_type": null,
"fields": [
{ "field_id": 1, "content": "Invoice Number", "value": "INV-1042", "is_table": false, "page": 1 }
],
"pages": [ { "page": 1, "status": "completed" } ],
"results_url": "https://invoiceextractor.ai/api/documents/extraction/abc123-def456-ghi789-jkl012"
}
}
Every request carries InvoiceExtractor-Signature: t=<unix time>,v1=<hex>, where v1 is HMAC SHA-256 of t + "." + raw request body with your endpoint's signing secret. Reject requests whose signature does not match or whose t is older than five minutes. The headers InvoiceExtractor-Event and InvoiceExtractor-Delivery carry the event type and a unique delivery ID you can use to ignore duplicates.
// PHP
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_INVOICEEXTRACTOR_SIGNATURE'] ?? ''), $sig);
$expected = hash_hmac('sha256', $sig['t'] . '.' . $body, getenv('INVOICEEXTRACTOR_WEBHOOK_SECRET'));
if (!hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int) $sig['t']) > 300) {
http_response_code(400);
exit;
}
# Python
import hmac, hashlib, time
parts = dict(p.split("=", 1) for p in request.headers["InvoiceExtractor-Signature"].split(","))
expected = hmac.new(secret.encode(), (parts["t"] + "." + request.get_data(as_text=True)).encode(), hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, parts["v1"]) and abs(time.time() - int(parts["t"])) <= 300
Answer with any 2xx status within 10 seconds. Other responses and timeouts are retried after 1 minute, 5 minutes, 15 minutes, 1 hour and 3 hours. Redirects are not followed. An endpoint that fails 15 deliveries in a row is disabled and can be enabled again in the dashboard, where you also see recent deliveries and can retry a failed one.
Webhooks are part of API access on the Pro plans.
Copy‑paste snippets to integrate invoice data extraction in minutes
# Upload document
curl -X POST https://invoiceextractor.ai/api/documents/upload \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "document=@/path/to/document.pdf"
# Extract data
curl -X POST https://invoiceextractor.ai/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://invoiceextractor.ai/api/documents/extraction/abc123-def456-ghi789-jkl012 \
-H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$apiToken = 'YOUR_API_TOKEN';
$apiBaseUrl = 'https://invoiceextractor.ai/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://invoiceextractor.ai/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://invoiceextractor.ai/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 invoice
if __name__ == "__main__":
result = process_document('/path/to/invoice.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:
Start turning your invoices into clean, structured spreadsheet data.
USD
per month
per month
$288 charged today
Choose speed vs accuracy when extracting
| Base AI Faster | 2,500 pages |
| Pro AI Best accuracy | 500 pages |
Scale invoice extraction across your whole team with automation.
USD
per month
per month
$888 charged today
Choose speed vs accuracy when extracting
| Base AI Faster | 10,000 pages |
| Pro AI Best accuracy | 2,000 pages |
Enterprise‑grade invoice extraction, security, and controls.
USD
per month
per month
$ charged today
Choose speed vs accuracy when extracting
| Base AI Faster | pages |
| Pro AI Best accuracy | pages |
Secure, encrypted checkout