Developers
Received (purchase) invoices extracted by the docparser pipeline.
GET /suppliers List received (purchase) invoicesGET /suppliers/items/{id} Get one received invoiceGET /suppliers/items/{id}/file Download the original purchase documentPOST /ingest/batches Upload a purchase document for extraction/suppliersList received (purchase) invoices
Purchase invoices extracted by the docparser pipeline. Date filters apply to `createdAt` (ingestion date), not the extracted invoice date.
Required permission:
purchases:documents.read (Purchases › Supplier invoices and expenses › Read)
Pagination: Parameters page and limit. The response includes total, page, limit, hasMore.
| Name | In | Type | Description |
|---|---|---|---|
state | query | string | Ingestion pipeline state, e.g. BOOKED, NEEDS_REVIEW. |
needsReview | query | boolean | |
dateFrom | query | string (date) | |
dateTo | query | string (date) | |
page | query | integer | Default: 1 |
limit | query | integer | Default: 50 · maximum: 500 |
200 List of supplier invoices · application/json
| Name | Type | Description |
|---|---|---|
items | object[] | |
items[].id | string | |
items[].companyId | string | |
items[].filename | string | |
items[].confidence | numbernullable | |
items[].state | string | |
items[].needsReview | boolean | |
items[].createdAt | string (date-time) | |
items[].updatedAt | string (date-time) | |
total | integer | Total items matching the filter. |
page | integer | Page returned (starts at 1). |
limit | integer | Page size applied. |
hasMore | boolean | There are more pages after this one. |
401 Missing or invalid Bearer token. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
403 Token lacks the required permission, or the resource is outside the token's tenant. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
429 Rate limit exceeded. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
curl -X GET "https://app.bm.consulting/api/v1/suppliers?limit=50" \
-H "Authorization: Bearer $BMC_TOKEN" const res = await fetch("https://app.bm.consulting/api/v1/suppliers?limit=50", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.BMC_TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json(); import os
import requests
res = requests.get(
"https://app.bm.consulting/api/v1/suppliers?limit=50",
headers={"Authorization": f"Bearer {os.environ['BMC_TOKEN']}"},
timeout=30,
)
res.raise_for_status()
data = res.json() /suppliers/items/{id}Get one received invoice
Full extracted detail including per-line fields. 404 for items outside your tenant.
Required permission:
purchases:documents.read (Purchases › Supplier invoices and expenses › Read)
Pagination: Not paginated: returns the full set.
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string |
200 Supplier invoice · application/json
| Name | Type | Description |
|---|---|---|
id | string | |
companyId | string | |
filename | string | |
confidence | numbernullable | |
issuerNif | stringnullable | |
issuerName | stringnullable | |
invoiceNumber | stringnullable | |
invoiceDate | string (date) | |
dueDate | string (date)nullable | |
baseAmount | numbernullable | |
vatAmount | numbernullable | |
total | numbernullable | |
currency | string | |
state | string | |
lines | object[] | |
lines[].description | stringnullable | |
lines[].quantity | numbernullable | |
lines[].unitPrice | numbernullable | |
lines[].lineTotal | numbernullable | |
lines[].vatRate | numbernullable | |
lines[].taxCode | stringnullable | SII regime code |
lines[].accountCode | stringnullable | PGC account code |
fileUrl | string (uri) | Exchange for a presigned download via GET /suppliers/items/{id}/file. |
401 Missing or invalid Bearer token. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
403 Token lacks the required permission, or the resource is outside the token's tenant. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
404 Resource not found (or belongs to a different tenant). · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
429 Rate limit exceeded. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
curl -X GET "https://app.bm.consulting/api/v1/suppliers/items/<id>" \
-H "Authorization: Bearer $BMC_TOKEN" const res = await fetch("https://app.bm.consulting/api/v1/suppliers/items/<id>", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.BMC_TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json(); import os
import requests
res = requests.get(
"https://app.bm.consulting/api/v1/suppliers/items/<id>",
headers={"Authorization": f"Bearer {os.environ['BMC_TOKEN']}"},
timeout=30,
)
res.raise_for_status()
data = res.json() /suppliers/items/{id}/fileDownload the original purchase document
Returns a redirect to a short-lived presigned URL for the original file.
Required permission:
purchases:documents.read (Purchases › Supplier invoices and expenses › Read)
Pagination: Not paginated: returns the full set.
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string |
302 Redirect to a presigned download URL
401 Missing or invalid Bearer token. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
403 Token lacks the required permission, or the resource is outside the token's tenant. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
404 Resource not found (or belongs to a different tenant). · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
429 Rate limit exceeded. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
curl -X GET "https://app.bm.consulting/api/v1/suppliers/items/<id>/file" \
-H "Authorization: Bearer $BMC_TOKEN" const res = await fetch("https://app.bm.consulting/api/v1/suppliers/items/<id>/file", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.BMC_TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json(); import os
import requests
res = requests.get(
"https://app.bm.consulting/api/v1/suppliers/items/<id>/file",
headers={"Authorization": f"Bearer {os.environ['BMC_TOKEN']}"},
timeout=30,
)
res.raise_for_status()
data = res.json() /ingest/batchesUpload a purchase document for extraction
Multipart upload of a purchase invoice (PDF/image). Queues it for OCR + extraction. L1 dedup by SHA-256 returns 200 for an identical re-upload. `companyId` is forced from the token.
Required permission:
documents:ingest.create (Documents › Document capture › Create)
Pagination: Not paginated: returns the full set.
multipart/form-data| Name | Type | Description |
|---|---|---|
filerequired | string (binary) | The document bytes. |
filename | string |
200 L1 dedup hit - identical file already ingested
201 File accepted and queued (returns batchId + itemId)
400 Missing file, unsupported type, or too large · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
401 Missing or invalid Bearer token. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
403 Token lacks the required permission, or the resource is outside the token's tenant. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
429 Rate limit exceeded. · application/json
| Name | Type | Description |
|---|---|---|
error | string | Human-readable error message |
required_permission | string | Present on 403 - the missing permission (area:resource.action) |
curl -X POST "https://app.bm.consulting/api/v1/ingest/batches" \
-H "Authorization: Bearer $BMC_TOKEN" \
-F "file=@documento.pdf" import { readFile } from "node:fs/promises";
const form = new FormData();
form.append("file", new Blob([await readFile("documento.pdf")]), "documento.pdf");
const res = await fetch("https://app.bm.consulting/api/v1/ingest/batches", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BMC_TOKEN}`,
},
body: form,
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json(); import os
import requests
res = requests.post(
"https://app.bm.consulting/api/v1/ingest/batches",
headers={"Authorization": f"Bearer {os.environ['BMC_TOKEN']}"},
files={"file": open("documento.pdf", "rb")},
timeout=30,
)
res.raise_for_status()
data = res.json()