API Reference

belege.ai API

A REST API for your own software: read bank transactions, search and download receipts and invoices, and push new documents straight into the belege.ai extraction pipeline. Predictable resource URLs, JSON everywhere, Bearer auth.

Base URL
https://belege.ai/api/v1
Authentication
Bearer belege_live_...
Version
v1 · OpenAPI 3.1
Format
JSON · UTF-8

Introduction

The belege.ai API is organized around REST. It has predictable, resource-oriented URLs, accepts form-encoded and multipart request bodies, returns JSON-encoded responses, and uses standard HTTP verbs, response codes, and authentication.

Use it to mirror your bookkeeping into your own systems: pull bank transactions and their matched documents, run full-text searches over every receipt and invoice we have collected, download the original files, and upload new documents that flow into the same extraction pipeline as Telegram and email.

Quick start

  1. 1Create a Public API token under Integrations → API tokens.
  2. 2Send it as a Bearer token in the Authorization header.
  3. 3Call GET /api/v1/me to confirm the token works.
curl https://belege.ai/api/v1/me \
  -H "Authorization: Bearer belege_live_..."
const res = await fetch("https://belege.ai/api/v1/me", {
  headers: { Authorization: "Bearer belege_live_..." },
});
const { data } = await res.json();
import requests

res = requests.get(
    "https://belege.ai/api/v1/me",
    headers={"Authorization": "Bearer belege_live_..."},
)
data = res.json()["data"]
200 OK
{
  "data": {
    "id": "7b1e9c44-0c2a-4e3b-9f10-2a6d8e5b1c33",
    "email": "marc@digitallyinduced.com",
    "firstname": "Marc",
    "lastname": "Scholten",
    "companyName": "digitally induced GmbH",
    "token": {
      "id": "f0a1b2c3-d4e5-46f7-8a9b-0c1d2e3f4a5b",
      "name": "Reporting",
      "scope": "public_api:read"
    },
    "organizations": [
      {
        "id": "c2f4a9d1-3b7e-4a82-9d10-5e6f7a8b9c01",
        "name": "digitally induced GmbH",
        "parentOrganizationId": null
      }
    ]
  }
}

Authentication

The API authenticates with personal Bearer tokens. Every request must carry an Authorization header — there is no cookie, session, or query-parameter auth. All requests must be made over HTTPS; plain HTTP requests fail.

Create a token under Integrations → API tokens. Pick "Public API", then choose the access level. The plaintext token is shown exactly once on creation — store it somewhere safe. Only a hash is kept in our database, so a lost token cannot be recovered, only replaced.

Token format

Public API tokens are prefixed with belege_live_ followed by a random secret. Treat them like passwords: never commit them to source control or expose them in client-side code.

Scopes

public_api:readread
Read every GET endpoint: account, transactions, documents, and file downloads.
public_api:writeread + write
Everything a read token can do, plus uploading documents via POST. Write implies read.

Keep tokens server-side

A token grants access to all transactions and documents the issuing user can see. Use it only from backends you control, and revoke it from Integrations the moment it leaks.

REQUEST HEADER
Authorization: Bearer belege_live_2yQ8fK3mZ7xR...nA4
curl https://belege.ai/api/v1/me \
  -H "Authorization: Bearer belege_live_..."
const res = await fetch("https://belege.ai/api/v1/me", {
  headers: {
    Authorization: "Bearer belege_live_...",
  },
});
import requests

session = requests.Session()
session.headers["Authorization"] = "Bearer belege_live_..."
res = session.get("https://belege.ai/api/v1/me")
401 Unauthorized
{
  "error": {
    "code": "invalid_bearer_token",
    "message": "The bearer token is invalid, expired, revoked, or missing the public API scope."
  }
}

Making requests

The base URL is https://belege.ai/api/v1. Read endpoints take query parameters; the upload endpoint takes multipart/form-data. Successful responses return 200 (or 201 for uploads) with a top-level data field. List endpoints add a pagination object.

Conventions

Envelopeobject
Single resources are wrapped in a data field. Lists return a data array plus a pagination object.
IDsstring
Transaction IDs are UUIDs. Document IDs are prefixed (see The document object) and combine a kind with a UUID.
Moneyinteger
Monetary amounts are integers in the minor unit of currency — e.g. amountCents 4187 is 41.87 EUR.
Datesstring
Calendar dates are ISO 8601 (YYYY-MM-DD). Timestamps are RFC 3339 UTC.
Scopingimplicit
A token only ever sees the issuing user's own data and the organizations they belong to. Filtering by an organization or transaction you cannot see returns 403.
curl -G https://belege.ai/api/v1/transactions \
  -H "Authorization: Bearer belege_live_..." \
  --data-urlencode "limit=2"
const res = await fetch(
  "https://belege.ai/api/v1/transactions?limit=2",
  { headers: { Authorization: "Bearer belege_live_..." } },
);
const { data, pagination } = await res.json();
import requests

res = requests.get(
    "https://belege.ai/api/v1/transactions",
    headers={"Authorization": "Bearer belege_live_..."},
    params={"limit": 2},
)
body = res.json()
200 OK
{
  "data": [
    { "id": "a1d4f8e2-...", "amountCents": -4187, "status": "waiting_for_user" },
    { "id": "b2e5a9f3-...", "amountCents": -1990, "status": "invoice_found" }
  ],
  "pagination": { "limit": 2, "offset": 0, "total": 184, "hasMore": true }
}

Errors

belege.ai uses conventional HTTP status codes. 2xx means success, 4xx means the request was rejected (a missing parameter, a bad token, a file that is too large), and 5xx means something failed on our side. Every error response has the same shape.

Error envelope

The error object always carries a stable, machine-readable code and a human-readable message. Branch on code; show or log message.

Status codes

StatusMeaningExample codes
400A parameter is missing or malformed.invalid_frominvalid_statusinvalid_transaction_idunsupported_file_typefile_signature_mismatch
401No valid bearer token was supplied.missing_bearer_tokeninvalid_bearer_token
403The token lacks the scope or cannot see the resource.insufficient_scopeforbidden
404The resource does not exist or is not visible.not_found
409The upload collides with an existing document.document_already_linked
413The uploaded file exceeds 128 MB.file_too_large
ERROR SHAPE
{
  "error": {
    "code": "invalid_status",
    "message": "status contains unsupported value 'paid'. Allowed values: unprocessed, agent_running, ..."
  }
}
413 Payload Too Large
{
  "error": {
    "code": "file_too_large",
    "message": "Maximum file size is 128 MB."
  }
}

Pagination

All list endpoints use limit/offset pagination and return a pagination object alongside the data array. Walk forward by increasing offset until hasMore is false.

Query parameters

limitinteger Optional

Page size, 1–200. Defaults to 50. Values above 200 are clamped.

offsetinteger Optional

Zero-based number of records to skip. Defaults to 0.

Pagination object

limitinteger
The page size that was applied.
offsetinteger
The offset that was applied.
totalinteger
Total number of records matching the filters.
hasMoreboolean
True when more records exist beyond this page.
# Page through every transaction, 200 at a time
curl -G https://belege.ai/api/v1/transactions \
  -H "Authorization: Bearer belege_live_..." \
  --data-urlencode "limit=200" \
  --data-urlencode "offset=0"
let offset = 0;
const all = [];
while (true) {
  const res = await fetch(
    "https://belege.ai/api/v1/transactions?limit=200&offset=" + offset,
    { headers: { Authorization: "Bearer belege_live_..." } },
  );
  const { data, pagination } = await res.json();
  all.push(...data);
  if (!pagination.hasMore) break;
  offset += pagination.limit;
}
offset, all = 0, []
while True:
    res = requests.get(
        "https://belege.ai/api/v1/transactions",
        headers={"Authorization": "Bearer belege_live_..."},
        params={"limit": 200, "offset": offset},
    ).json()
    all += res["data"]
    if not res["pagination"]["hasMore"]:
        break
    offset += res["pagination"]["limit"]
PAGINATION
{
  "pagination": {
    "limit": 200,
    "offset": 0,
    "total": 184,
    "hasMore": false
  }
}

Current account

GET/api/v1/mepublic_api:read

Returns the user the token belongs to, the token's own metadata, and every organization the token can see. Use it to verify a token and to discover the organization IDs you can pass as filters.

Returns

A data object with the user, a token summary (id, name, scope), and an organizations array.

curl https://belege.ai/api/v1/me \
  -H "Authorization: Bearer belege_live_..."
const res = await fetch("https://belege.ai/api/v1/me", {
  headers: { Authorization: "Bearer belege_live_..." },
});
const { data } = await res.json();
import requests

res = requests.get(
    "https://belege.ai/api/v1/me",
    headers={"Authorization": "Bearer belege_live_..."},
)
data = res.json()["data"]
200 OK
{
  "data": {
    "id": "7b1e9c44-0c2a-4e3b-9f10-2a6d8e5b1c33",
    "email": "marc@digitallyinduced.com",
    "firstname": "Marc",
    "lastname": "Scholten",
    "companyName": "digitally induced GmbH",
    "token": {
      "id": "f0a1b2c3-d4e5-46f7-8a9b-0c1d2e3f4a5b",
      "name": "Reporting",
      "scope": "public_api:read"
    },
    "organizations": [
      {
        "id": "c2f4a9d1-3b7e-4a82-9d10-5e6f7a8b9c01",
        "name": "digitally induced GmbH",
        "parentOrganizationId": null
      }
    ]
  }
}

The transaction object

A transaction is a single line from a connected bank account or payment provider. Each one moves through a status lifecycle as belege.ai finds and matches its document.

Attributes

idstring
Unique identifier (UUID) for the transaction.
organizationIdstring | null
Organization the transaction belongs to, if any.
transactionDatestring
Value date of the transaction (YYYY-MM-DD).
bookingDatestring | null
Date the bank booked the transaction, if known.
amountCentsinteger
Amount in the minor unit of currency. May be negative for outgoing payments.
currencystring
ISO 4217 currency code, e.g. EUR.
descriptionstring
Bank-provided description or purpose text.
counterpartystring | null
Name of the other party, when the bank provides it.
ibanstring | null
Counterparty IBAN, when available.
referencestring | null
End-to-end reference or payment reference.
transactionTypestring | null
Provider-specific type, e.g. debit or credit.
bankAccountstring | null
Human-readable name of the source account.
bankAccountIdstring | null
UUID of the source bank account.
statusstring
Lifecycle of the document search. One of: unprocessedagent_runningagent_failedwaiting_for_userwaiting_for_providerinvoice_foundignored
statusNotestring | null
Optional note explaining the current status.
createdAtstring
When the transaction was imported (RFC 3339).
updatedAtstring
When the transaction last changed (RFC 3339).
documentsarray
Matched documents. Only present when retrieving a single transaction.
THE TRANSACTION OBJECT
{
  "id": "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34",
  "organizationId": "c2f4a9d1-3b7e-4a82-9d10-5e6f7a8b9c01",
  "transactionDate": "2026-03-04",
  "bookingDate": "2026-03-05",
  "amountCents": -4187,
  "currency": "EUR",
  "description": "AWS EMEA SARL",
  "counterparty": "Amazon Web Services",
  "iban": "LU12345678901234567890",
  "reference": "EU-INV-2026-0042",
  "transactionType": "debit",
  "bankAccount": "Revolut Business",
  "bankAccountId": "9d3b1c7a-2e4f-4a6b-8c10-1d2e3f4a5b6c",
  "status": "waiting_for_user",
  "statusNote": null,
  "createdAt": "2026-03-05T08:12:44Z",
  "updatedAt": "2026-03-05T08:12:44Z"
}

List transactions

GET/api/v1/transactionspublic_api:read

Returns a paginated list of transactions visible to the token, newest first. Combine the filters below to narrow the result; all are optional.

Query parameters

qstring Optional

Full-text search over description, counterparty, and reference. Minimum 2 characters.

fromstring Optional

Only transactions on or after this date (YYYY-MM-DD).

tostring Optional

Only transactions on or before this date (YYYY-MM-DD).

statusstring Optional

Comma-separated statuses, e.g. waiting_for_user,invoice_found.

organizationIdstring Optional

Restrict to one visible organization (UUID).

limitinteger Optional

Page size, 1–200. Defaults to 50.

offsetinteger Optional

Zero-based offset. Defaults to 0.

Returns

A data array of transaction objects plus a pagination object.

curl -G https://belege.ai/api/v1/transactions \
  -H "Authorization: Bearer belege_live_..." \
  --data-urlencode "q=AWS" \
  --data-urlencode "from=2026-01-01" \
  --data-urlencode "status=waiting_for_user,invoice_found" \
  --data-urlencode "limit=25"
const params = new URLSearchParams({
  q: "AWS",
  from: "2026-01-01",
  status: "waiting_for_user,invoice_found",
  limit: "25",
});
const res = await fetch(
  "https://belege.ai/api/v1/transactions?" + params,
  { headers: { Authorization: "Bearer belege_live_..." } },
);
const { data, pagination } = await res.json();
import requests

res = requests.get(
    "https://belege.ai/api/v1/transactions",
    headers={"Authorization": "Bearer belege_live_..."},
    params={
        "q": "AWS",
        "from": "2026-01-01",
        "status": "waiting_for_user,invoice_found",
        "limit": 25,
    },
)
body = res.json()
200 OK
{
  "data": [
    {
      "id": "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34",
      "organizationId": "c2f4a9d1-3b7e-4a82-9d10-5e6f7a8b9c01",
      "transactionDate": "2026-03-04",
      "bookingDate": "2026-03-05",
      "amountCents": -4187,
      "currency": "EUR",
      "description": "AWS EMEA SARL",
      "counterparty": "Amazon Web Services",
      "iban": "LU12345678901234567890",
      "reference": "EU-INV-2026-0042",
      "transactionType": "debit",
      "bankAccount": "Revolut Business",
      "bankAccountId": "9d3b1c7a-2e4f-4a6b-8c10-1d2e3f4a5b6c",
      "status": "waiting_for_user",
      "statusNote": null,
      "createdAt": "2026-03-05T08:12:44Z",
      "updatedAt": "2026-03-05T08:12:44Z"
    }
  ],
  "pagination": { "limit": 25, "offset": 0, "total": 1, "hasMore": false }
}

Synchronize transaction changes

GET/api/v1/transactions/changespublic_api:read

Returns transactions created or updated after a stored synchronization timestamp. The first response fixes a watermark, so changes arriving while you paginate are held for the next run instead of shifting pages.

Query parameters

sincestring Optional

Required on the first page: an RFC 3339 timestamp. Results are strictly newer than this value.

cursorstring Optional

For subsequent pages, pass nextCursor exactly as returned. Do not send since with a cursor.

limitinteger Optional

Page size, 1–200. Defaults to 200.

Safe synchronization loop

Start with your last completed watermark as since. Follow nextCursor until hasMore is false. Only then persist the response watermark as the since value for the next run. Cursors are opaque and must not be edited.

Use this endpoint for scheduled imports

The regular transaction list is ordered for people browsing newest transactions. This change feed is ordered by updatedAt and id for reliable machine synchronization.

curl -G https://belege.ai/api/v1/transactions/changes \
  -H "Authorization: Bearer belege_live_..." \
  --data-urlencode "since=2026-08-06T04:30:07Z" \
  --data-urlencode "limit=200"
let params = new URLSearchParams({
  since: "2026-08-06T04:30:07Z",
  limit: "200",
});
let watermark;
while (true) {
  const res = await fetch(
    "https://belege.ai/api/v1/transactions/changes?" + params,
    { headers: { Authorization: "Bearer belege_live_..." } },
  );
  const { data, sync } = await res.json();
  await upsertTransactions(data);
  watermark = sync.watermark;
  if (!sync.hasMore) break;
  params = new URLSearchParams({ cursor: sync.nextCursor, limit: "200" });
}
await saveCompletedWatermark(watermark);
import requests

params = {"since": "2026-08-06T04:30:07Z", "limit": 200}
while True:
    body = requests.get(
        "https://belege.ai/api/v1/transactions/changes",
        headers={"Authorization": "Bearer belege_live_..."},
        params=params,
    ).json()
    upsert_transactions(body["data"])
    if not body["sync"]["hasMore"]:
        save_completed_watermark(body["sync"]["watermark"])
        break
    params = {"cursor": body["sync"]["nextCursor"], "limit": 200}
200 OK
{
  "data": [
    {
      "id": "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34",
      "transactionDate": "2026-08-06",
      "amountCents": -4187,
      "currency": "EUR",
      "description": "AWS EMEA SARL",
      "status": "invoice_found",
      "createdAt": "2026-08-06T18:10:00Z",
      "updatedAt": "2026-08-06T19:42:11Z"
    }
  ],
  "sync": {
    "since": "2026-08-06T04:30:07Z",
    "watermark": "2026-08-07T08:15:30.123Z",
    "nextCursor": null,
    "hasMore": false
  }
}

Retrieve a transaction

GET/api/v1/transactions/{transactionId}public_api:read

Fetches a single transaction by UUID, with its matched documents embedded under documents. Returns 404 if the transaction does not exist and 403 if the token cannot see it.

Path parameters

transactionIdstring Required

UUID of the transaction to retrieve.

Returns

A data object: the transaction, plus a documents array of matched document objects.

curl https://belege.ai/api/v1/transactions/a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34 \
  -H "Authorization: Bearer belege_live_..."
const id = "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34";
const res = await fetch(
  "https://belege.ai/api/v1/transactions/" + id,
  { headers: { Authorization: "Bearer belege_live_..." } },
);
const { data } = await res.json();
import requests

tx_id = "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34"
res = requests.get(
    f"https://belege.ai/api/v1/transactions/{tx_id}",
    headers={"Authorization": "Bearer belege_live_..."},
)
data = res.json()["data"]
200 OK
{
  "data": {
    "id": "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34",
    "transactionDate": "2026-03-04",
    "amountCents": -4187,
    "currency": "EUR",
    "description": "AWS EMEA SARL",
    "counterparty": "Amazon Web Services",
    "status": "invoice_found",
    "createdAt": "2026-03-05T08:12:44Z",
    "updatedAt": "2026-03-06T09:30:11Z",
    "documents": [
      {
        "id": "invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44",
        "sourceKind": "invoice_document",
        "source": "gmail",
        "fileName": "aws-invoice-2026-03.pdf",
        "contentType": "application/pdf",
        "documentType": "invoice",
        "status": "matched",
        "fileUrl": "/api/v1/documents/invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44/file"
      }
    ]
  }
}

The document object

A document is any receipt, invoice, or file belege.ai has collected — from email, uploads, Telegram, connected platforms, or generated on your behalf. Documents from three internal stores are presented through one unified shape.

Document IDs are prefixed

Unlike transactions, a document id combines its source kind with a UUID, e.g. invoice_document:8f3c…. Always pass the full prefixed id to the retrieve and download endpoints.

Attributes

idstring
Prefixed identifier, e.g. invoice_document:<uuid>. Use it for retrieve and download.
sourceKindstring
Which internal store the document lives in. One of: invoice_documentdocument_extractionbusiness_meal_document
sourcestring
Where the document originally came from. One of: gmailimapstripemocomollieshopifyteslamicrosofteigenbeleguploadtelegrambewirtungbrowseremail_exportlexwarereconciliationother
fileNamestring
Original file name.
contentTypestring
MIME type, e.g. application/pdf or image/jpeg.
fileSizeBytesinteger | null
Size of the stored file in bytes, when known.
documentDatestring | null
Document or invoice date (YYYY-MM-DD), when extracted.
vendorstring | null
Detected vendor, merchant, or sender.
amountCentsinteger | null
Detected gross amount in minor units, when extracted.
currencystring
Currency of amountCents. Defaults to EUR.
transactionIdstring | null
UUID of the linked transaction, if matched.
organizationIdstring | null
Organization the document belongs to, if any.
summarystring | null
Short summary, email subject, or business purpose.
documentTypestring
Classified type. One of: invoicereceiptcredit_notecontractbank_statementmulti_receipt_pdfreisekostenabrechnungbewirtungsbelegother
statusstring
Match / extraction state. One of: matchedunmatchedextractingfailed
createdAtstring
When the document was collected (RFC 3339).
fileUrlstring
Relative path to download the raw bytes.
THE DOCUMENT OBJECT
{
  "id": "invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44",
  "sourceKind": "invoice_document",
  "source": "gmail",
  "fileName": "aws-invoice-2026-03.pdf",
  "contentType": "application/pdf",
  "fileSizeBytes": 48211,
  "documentDate": "2026-03-04",
  "vendor": "no-reply@aws.amazon.com",
  "amountCents": null,
  "currency": "EUR",
  "transactionId": "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34",
  "organizationId": "c2f4a9d1-3b7e-4a82-9d10-5e6f7a8b9c01",
  "summary": "Your AWS invoice for March 2026",
  "documentType": "invoice",
  "status": "matched",
  "createdAt": "2026-03-06T09:30:11Z",
  "fileUrl": "/api/v1/documents/invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44/file"
}

List documents

GET/api/v1/documentspublic_api:read

Returns a paginated list of documents visible to the token, newest first. Filters are optional and combine with AND.

Query parameters

qstring Optional

Full-text search over file name, vendor, and summary. Minimum 2 characters.

typestring Optional

Comma-separated document types, e.g. invoice,receipt.

sourcestring Optional

Comma-separated sources, e.g. gmail,upload.

transactionIdstring Optional

Only documents linked to this transaction (UUID).

organizationIdstring Optional

Restrict to one visible organization (UUID).

limitinteger Optional

Page size, 1–200. Defaults to 50.

offsetinteger Optional

Zero-based offset. Defaults to 0.

Returns

A data array of document objects plus a pagination object.

curl -G https://belege.ai/api/v1/documents \
  -H "Authorization: Bearer belege_live_..." \
  --data-urlencode "type=invoice,receipt" \
  --data-urlencode "source=gmail,upload" \
  --data-urlencode "limit=50"
const params = new URLSearchParams({
  type: "invoice,receipt",
  source: "gmail,upload",
  limit: "50",
});
const res = await fetch(
  "https://belege.ai/api/v1/documents?" + params,
  { headers: { Authorization: "Bearer belege_live_..." } },
);
const { data, pagination } = await res.json();
import requests

res = requests.get(
    "https://belege.ai/api/v1/documents",
    headers={"Authorization": "Bearer belege_live_..."},
    params={"type": "invoice,receipt", "source": "gmail,upload", "limit": 50},
)
body = res.json()
200 OK
{
  "data": [
    {
      "id": "invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44",
      "sourceKind": "invoice_document",
      "source": "gmail",
      "fileName": "aws-invoice-2026-03.pdf",
      "contentType": "application/pdf",
      "documentDate": "2026-03-04",
      "vendor": "no-reply@aws.amazon.com",
      "transactionId": "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34",
      "documentType": "invoice",
      "status": "matched",
      "fileUrl": "/api/v1/documents/invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44/file"
    }
  ],
  "pagination": { "limit": 50, "offset": 0, "total": 1, "hasMore": false }
}

Upload a document

POST/api/v1/documentspublic_api:write

Uploads a file as multipart/form-data. The document enters the same extraction pipeline as email and Telegram: it is OCR'd, classified, and — if you link a transaction — matched. Requires a write token.

Body (multipart/form-data)

filefile Required

The document. PDF, JPG, JPEG, or PNG, up to 128 MB. The byte signature must match the extension.

transactionIdstring Optional

Link the upload to this transaction (UUID). Must be visible to the token.

organizationIdstring Optional

Assign to this organization (UUID). Must match the transaction's organization if both are given.

notestring Optional

Free-text note stored with the document.

Returns

201 Created with the new document under data. queued indicates whether extraction was scheduled. Duplicate files already linked elsewhere return 409 document_already_linked.

curl -X POST https://belege.ai/api/v1/documents \
  -H "Authorization: Bearer belege_live_..." \
  -F "file=@invoice.pdf" \
  -F "transactionId=a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34" \
  -F "note=Imported from our ERP"
const form = new FormData();
form.append("file", fileInput.files[0]);
form.append("transactionId", "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34");

const res = await fetch("https://belege.ai/api/v1/documents", {
  method: "POST",
  headers: { Authorization: "Bearer belege_live_..." },
  body: form,
});
const { data } = await res.json();
import requests

with open("invoice.pdf", "rb") as f:
    res = requests.post(
        "https://belege.ai/api/v1/documents",
        headers={"Authorization": "Bearer belege_live_..."},
        files={"file": ("invoice.pdf", f, "application/pdf")},
        data={"transactionId": "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34"},
    )
data = res.json()["data"]
201 Created
{
  "data": {
    "id": "document_extraction:b9d1e3f5-7a2c-4b6d-8e90-1f2a3b4c5d6e",
    "sourceKind": "document_extraction",
    "fileName": "invoice.pdf",
    "contentType": "application/pdf",
    "fileSizeBytes": 50122,
    "status": "pending",
    "transactionId": "a1d4f8e2-9c3b-4f6a-8e21-7b9c0d1e2f34",
    "organizationId": "c2f4a9d1-3b7e-4a82-9d10-5e6f7a8b9c01",
    "queued": true,
    "fileUrl": "/api/v1/documents/document_extraction:b9d1e3f5-7a2c-4b6d-8e90-1f2a3b4c5d6e/file"
  }
}

Retrieve a document

GET/api/v1/documents/{documentId}public_api:read

Fetches a single document's metadata by its prefixed id. To fetch the bytes, use the download endpoint below.

Path parameters

documentIdstring Required

Prefixed id, e.g. invoice_document:<uuid>, document_extraction:<uuid>, or business_meal_document:<uuid>.

Returns

A data object holding the document. Malformed ids return 400 invalid_document_id.

curl https://belege.ai/api/v1/documents/invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44 \
  -H "Authorization: Bearer belege_live_..."
const id = "invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44";
const res = await fetch(
  "https://belege.ai/api/v1/documents/" + encodeURIComponent(id),
  { headers: { Authorization: "Bearer belege_live_..." } },
);
const { data } = await res.json();
import requests

doc_id = "invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44"
res = requests.get(
    f"https://belege.ai/api/v1/documents/{doc_id}",
    headers={"Authorization": "Bearer belege_live_..."},
)
data = res.json()["data"]
200 OK
{
  "data": {
    "id": "invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44",
    "sourceKind": "invoice_document",
    "source": "gmail",
    "fileName": "aws-invoice-2026-03.pdf",
    "contentType": "application/pdf",
    "fileSizeBytes": 48211,
    "documentDate": "2026-03-04",
    "vendor": "no-reply@aws.amazon.com",
    "documentType": "invoice",
    "status": "matched",
    "createdAt": "2026-03-06T09:30:11Z",
    "fileUrl": "/api/v1/documents/invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44/file"
  }
}

Download a file

GET/api/v1/documents/{documentId}/filepublic_api:read

Streams the raw bytes of a document with its original Content-Type and file name. This is the URL exposed as fileUrl on every document object. Follow redirects.

Path parameters

documentIdstring Required

Prefixed id of the document to download.

Returns

The binary file (application/pdf, image/jpeg, or image/png) with a Content-Disposition file name.

curl -L https://belege.ai/api/v1/documents/invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44/file \
  -H "Authorization: Bearer belege_live_..." \
  -o invoice.pdf
const id = "invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44";
const res = await fetch(
  "https://belege.ai/api/v1/documents/" + encodeURIComponent(id) + "/file",
  { headers: { Authorization: "Bearer belege_live_..." } },
);
const blob = await res.blob();
import requests

doc_id = "invoice_document:e7c2b1a9-5d4f-4a3b-9c10-2e6f8a1b3c44"
res = requests.get(
    f"https://belege.ai/api/v1/documents/{doc_id}/file",
    headers={"Authorization": "Bearer belege_live_..."},
)
with open("invoice.pdf", "wb") as f:
    f.write(res.content)
200 OK
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: inline; filename="aws-invoice-2026-03.pdf"

%PDF-1.7
%...binary contents...

OpenAPI schema

GET/api/v1/openapi.jsonpublic

A machine-readable OpenAPI 3.1 description of every endpoint, parameter, and schema on this page. It needs no authentication, so you can generate typed clients and SDKs directly from it.

Point Stainless, openapi-generator, Speakeasy, or your tool of choice at the URL to scaffold a client in your language.

GENERATE A CLIENT
# No auth required — generate a typed client
npx @openapitools/openapi-generator-cli generate \
  -i https://belege.ai/api/v1/openapi.json \
  -g typescript-fetch \
  -o ./belege-client