Documents

Inbound source files — receipts and purchase invoices, received by email ingestion or uploaded through the API. Documents ride the expenses:read ability; the /documents endpoints themselves are read-only — metadata plus a binary download of the stored file.

Operations

Method & path Ability
GET /api/v1/documents expenses:read
GET /api/v1/documents/{document} expenses:read
GET /api/v1/documents/{document}/download expenses:read

Get document metadata

curl https://billey.nl/api/v1/documents/501 \
  -H "Authorization: Bearer $TOKEN"
{
  "data": {
    "id": 501,
    "source": "email",
    "original_filename": "receipt-2026-07.pdf",
    "mime_type": "application/pdf",
    "has_pdf_attachment": true,
    "received_at": "2026-07-21T09:02:00Z",
    "sender_email": "facturen@leverancier.nl",
    "email_subject": "Uw factuur"
  }
}

Download the file

GET /api/v1/documents/{document}/download streams the raw stored file back as a binary attachment (not JSON). The Content-Disposition header carries the original filename.

curl -L https://billey.nl/api/v1/documents/501/download \
  -H "Authorization: Bearer $TOKEN" \
  -o receipt.pdf

Creating a document

There is no standalone POST /documents. A document enters an administration by email ingestion or by uploading a file when you create an expense as multipart/form-data — that stores the file (source upload) and links it to the new expense in a single call. Its searchable text is extracted asynchronously, so a freshly uploaded document starts at extraction_status: processing. To link an already-stored document to a new expense instead, pass its id as document_id.

See the OpenAPI spec for the full field list.

Something inaccurate or missing? support@billey.nl