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 connected accounting system.
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 → General tab, in the External API Key section. 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 |
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
POST /api/v1/companies/{companyReferenceId}/documents/{documentId}/send
Triggers the send flow — Finpilo runs the Send to Accounting workflow, which posts the document to the entity's connection (or the workspace default connection if the entity has not picked one). See Connections.
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 the receiving system (if any).
Response 400 — the send could not run, for example when no connection is configured or the document was already sent and resend was not set:
{ "error": "description of the failure" }
Document payload schema
This is the structure returned by the document endpoints. It is also the default payload the Send to Accounting workflow posts to your system when a document is sent — admins can adjust that payload in the workflow (see Connections).
{
"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).
Receiving sent documents
When Finpilo sends a document to your system, follow this typical flow:
- Receive the HTTP POST. The body is
application/jsonmatching the payload schema above. - The request carries the authentication configured on the connection — a Bearer token, Basic credentials, or a custom header (see Connections). 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. Finpilo stores it in the document's Accounting Reference field. 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 send request includes:
Content-Type: application/json
plus the authentication header from the connection: Authorization: Bearer <token> for Bearer auth, Authorization: Basic <credentials> for Basic auth, or the custom header you named on the connection. A connection with No auth sends no authentication header.
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" }.