External API
Finpilo provides an external API for integrating other systems — accounting software, ERP platforms, or custom internal tools — with your workspace.
This page is a reference for developers or integration consultants building a connection between Finpilo and another system.
What you can do through the API
- Sync partners (suppliers) into Finpilo from your accounting system.
- Sync dimension values (cost centers, VAT codes, posting accounts) from your accounting system.
- Read processed documents, including extracted data, line items, and assigned dimensions.
- Download the original file of any document.
- Trigger a send of a validated document to the configured webhook.
Documents are created in Finpilo only through the Portal UI or email forwarding — you cannot create documents through the API. Partner and dimension data, however, can flow in both directions.
Authentication
All API requests must include an X-API-Key header containing your workspace API key.
X-API-Key: fp_your_workspace_key
Generate the key in Workspace Settings → API tab. See Workspace Settings for instructions.
The key is scoped to a single workspace. All resource access is automatically limited to that workspace — you cannot access entities or documents outside it.
Reference IDs
Most endpoints use your own reference IDs (the string identifiers you set when creating entities, partners, or dimension values in Finpilo) rather than internal UUIDs. This makes integration simpler — use the same IDs your accounting system uses.
companyReferenceId— the entity's reference ID (e.g.,ENT-00001).referenceIdon suppliers and dimension values — the identifier you chose.
Documents are the exception — they are addressed by their internal UUID, returned by the list endpoint.
Partners (Suppliers)
Endpoint prefix: /api/v1/companies/{companyReferenceId}/suppliers
Batch upsert partners
POST /api/v1/companies/{companyReferenceId}/suppliers
Creates new partners or updates existing ones. Match is by referenceId. Each item is processed independently — failures do not roll back other successful items.
Limits: 1 to 10,000 items per request.
Request body:
[
{
"referenceId": "SUP-001",
"legalName": "Acme Supplies OÜ",
"regNo": "12345678",
"vatNo": "EE123456789",
"legalAddress": "Tallinn, Estonia",
"bankAccounts": ["EE382200221020145685"]
}
]
Required fields: referenceId, legalName. All others are optional.
Response 200:
{
"created": 2,
"updated": 1,
"failed": 0,
"results": [
{ "referenceId": "SUP-001", "status": "created" },
{ "referenceId": "SUP-002", "status": "updated" },
{ "referenceId": "SUP-003", "status": "failed", "error": "..." }
]
}
List partners
GET /api/v1/companies/{companyReferenceId}/suppliers
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | Page number |
pageSize |
int | 100 | Items per page, max 1000 |
updatedSince |
ISO 8601 UTC | — | Only return partners updated after this timestamp |
Get single partner
GET /api/v1/companies/{companyReferenceId}/suppliers/{referenceId}
Response 200:
{
"id": "uuid",
"referenceId": "SUP-001",
"legalName": "Acme Supplies OÜ",
"regNo": "12345678",
"vatNo": "EE123456789",
"legalAddress": "Tallinn, Estonia",
"bankAccounts": ["EE382200221020145685"],
"createdAt": "ISO 8601",
"updatedAt": "ISO 8601"
}
Dimension values
Endpoint prefix: /api/v1/companies/{companyReferenceId}/dimensions/{dimensionReferenceId}/items
dimensionReferenceId is the reference ID of the dimension as set in the entity's Dimensions tab.
Batch upsert dimension values
POST /api/v1/companies/{companyReferenceId}/dimensions/{dimensionReferenceId}/items
Same partial-success semantics as partners.
Limits: 1 to 10,000 items per request.
Request body:
[
{
"referenceId": "DIM-00001",
"name": "Administration",
"description": "Accounting, legal, management fees"
}
]
Required fields: referenceId, name. description is optional.
List dimension values
GET /api/v1/companies/{companyReferenceId}/dimensions/{dimensionReferenceId}/items
Query parameters: page, pageSize (max 1000), updatedSince — same as partners.
Get single dimension value
GET /api/v1/companies/{companyReferenceId}/dimensions/{dimensionReferenceId}/items/{referenceId}
Response 200:
{
"id": "uuid",
"referenceId": "DIM-00001",
"name": "Administration",
"description": "Accounting, legal, management fees",
"allocationListReferenceId": "DEPT",
"createdAt": "ISO 8601",
"updatedAt": "ISO 8601"
}
Documents
Endpoint prefix: /api/v1/companies/{companyReferenceId}/documents
Documents are read-only through the API. They are created only through upload or email in the Finpilo portal.
List documents
GET /api/v1/companies/{companyReferenceId}/documents
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | Page number |
pageSize |
int | 50 | Items per page, max 500 |
status |
string | — | Filter by status (e.g., validated, sent) |
documentType |
string | — | Filter by document type name |
issuedFrom |
ISO 8601 | — | Issue date range start |
issuedTo |
ISO 8601 | — | Issue date range end |
sentOnly |
bool | — | If true, only documents already sent via webhook |
Response 200: array of document payload objects (see schema below).
Get single document
GET /api/v1/companies/{companyReferenceId}/documents/{documentId}
Returns the full document including all line items and dimension allocations.
Download original file
GET /api/v1/companies/{companyReferenceId}/documents/{documentId}/file
Returns the original uploaded file as a binary stream. Content-Type matches the original upload (PDF, JPEG, PNG).
Finpilo does not convert or re-encode files — you receive exactly what was uploaded.
Send document to webhook
POST /api/v1/companies/{companyReferenceId}/documents/{documentId}/send
Triggers the send flow — Finpilo posts the document to the configured webhook (entity webhook if set, workspace webhook otherwise).
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
resend |
bool | false | If true, allows re-sending a document that was already sent |
Response 200:
{
"success": true,
"accountingReferenceId": "INV-2026-0042"
}
accountingReferenceId is the value returned by your webhook endpoint (if any).
Response 400 — send failed:
{ "error": "Custom webhook is enabled for this entity but no URL is configured." }
Document payload schema
This is the structure returned by the document endpoints and also sent as the webhook body when a document is sent.
{
"documentId": "3fa0b1c2-d3e4-5f67-8901-abcdef123456",
"documentType": "Invoice",
"direction": "Incoming",
"documentNumber": "INV-2025-0042",
"issueDate": "2025-01-15T00:00:00Z",
"dueDate": "2025-02-15T00:00:00Z",
"servicePeriodStartDate": "2025-01-01T00:00:00Z",
"servicePeriodEndDate": "2025-01-31T00:00:00Z",
"currency": "EUR",
"supplierName": "Acme Supplies OÜ",
"supplierRegNumber": "12345678",
"supplierVatNumber": "EE123456789",
"supplierAddress": "Tallinn, Estonia",
"supplierBankAccounts": ["EE382200221020145685"],
"supplierReferenceId": "SUP-001",
"recipientName": "My Company SIA",
"recipientRegNumber": "40003012345",
"recipientVatNumber": "LV40003012345",
"recipientAddress": "Riga, Latvia",
"recipientBankAccounts": null,
"recipientReferenceId": "ENT-00001",
"lineItemsSubtotalExcludingTax": 1000.00,
"allowancesAmountExcludingTax": 0,
"chargesAmountExcludingTax": 0,
"retentionAmountExcludingTax": 0,
"totalExcludingTax": 1000.00,
"taxAmount": 200.00,
"totalIncludingTax": 1200.00,
"prepaidAmountIncludingTax": null,
"payableAmountIncludingTax": 1200.00,
"comment": null,
"validatedAt": "2025-01-20T09:15:00Z",
"entityName": "My Company SIA",
"fileUrl": "https://docmanager-api.../api/v1/companies/ENT-00001/documents/3fa0b1c2-.../file",
"lineItems": [
{
"position": 1,
"title": "Consulting services",
"description": "January 2025",
"supplierCode": "CONS-001",
"unit": "h",
"quantity": 10.0,
"unitPriceExcludingTax": 100.00,
"totalExcludingTax": 1000.00,
"taxRate": 20.0,
"taxAmount": 200.00,
"totalIncludingTax": 1200.00,
"allocations": [
{
"allocationListReferenceId": "DEPT",
"dimensionName": "Department",
"code": "IT",
"name": "IT Department",
"description": null
}
]
}
],
"allocations": []
}
Fields with no data are null (never omitted). lineItems and allocations are always arrays (empty [] if none).
Webhook integration flow
When Finpilo sends a document to your webhook, follow this typical flow:
- Receive the HTTP POST. The body is
application/jsonmatching the payload schema above. - If you configured an API key in the Finpilo webhook settings, it arrives in the
Authorization: Bearer <key>header. Verify it before processing. - Create a record in your system using the structured data.
- Fetch the original file from
fileUrlusing your Finpilo workspace API key (the same one used for all API calls). - Attach the file to your record.
- Return a JSON response with
accountingReferenceIdset to your internal record ID. An empty200 OKresponse is also valid if you do not track the reference.
Finpilo waits up to 30 seconds for your response. Requests that exceed this are marked as failed.
Headers sent by Finpilo
Every webhook request includes:
Content-Type: application/json
Authorization: Bearer <api-key>
The Authorization header is only included if you configured an API key in the webhook settings.
Error responses
| Status | Meaning |
|---|---|
401 Unauthorized |
Missing or invalid X-API-Key |
404 Not Found |
Reference ID not found within the workspace |
400 Bad Request |
Validation failure (empty batch, batch > 10,000 items, send errors) |
All error responses use the shape { "error": "description" }.