Invoices
Outgoing invoices and credit notes, with their line items and lifecycle. Each invoice is returned with its embedded client summary and line items.
These pages show the shape; the OpenAPI spec has every field, constraint, and error.
Operations
| Method & path | Ability |
|---|---|
GET /api/v1/invoices |
invoices:read |
GET /api/v1/invoices/{invoice} |
invoices:read |
GET /api/v1/invoices/{invoice}/pdf |
invoices:read |
POST /api/v1/invoices |
invoices:write |
PATCH /api/v1/invoices/{invoice} |
invoices:write |
DELETE /api/v1/invoices/{invoice} |
invoices:write |
POST /api/v1/invoices/{invoice}/credit-note |
invoices:write |
POST /api/v1/invoices/{invoice}/send |
invoices:write |
POST /api/v1/invoices/{invoice}/mark-sent |
invoices:write |
POST /api/v1/invoices/{invoice}/mark-paid |
invoices:write |
POST /api/v1/invoices/{invoice}/revert-to-draft |
invoices:write |
Create an invoice
POST /api/v1/invoices creates a draft. Required: client_id, currency, invoice_date, due_date, and at least one line in items. Each line needs description, quantity, unit_price, and a btw_percentage of 0, 9, or 21. invoice_number is optional — omit it and the next number is allocated automatically. As a create, it takes an Idempotency-Key.
curl -X POST https://billey.nl/api/v1/invoices \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"client_id": 7,
"currency": "EUR",
"invoice_date": "2026-07-21",
"due_date": "2026-08-04",
"notes": "Thanks for your business.",
"items": [
{ "description": "Consulting", "quantity": "10", "unit_price": "103.31", "btw_percentage": 21 }
]
}'
{
"data": {
"id": 42,
"invoice_number": "2026-0042",
"status": "draft",
"is_credit_note": false,
"currency": "EUR",
"invoice_date": "2026-07-21",
"due_date": "2026-08-04",
"subtotal": "1033.10",
"btw_total": "217.05",
"total": "1250.15",
"reverse_charge_applied": false,
"tax_treatment": "standard",
"client": { "id": 7, "name": "Example Client B.V." },
"line_items": [
{
"id": 1,
"description": "Consulting",
"quantity": "10.00",
"unit_price": "103.31",
"btw_percentage": "21.00",
"btw_amount": "217.05",
"line_total": "1033.10"
}
]
}
}
You can optionally pass time_entry_ids on create to claim uninvoiced time entries onto the new invoice.
Download the PDF
GET /api/v1/invoices/{invoice}/pdf renders and returns the same PDF the web app's "Download PDF" button produces — same branding, template, and payment QR code (not JSON).
curl -L https://billey.nl/api/v1/invoices/42/pdf \
-H "Authorization: Bearer $TOKEN" \
-o invoice.pdf
This route carries its own, tighter rate limit — see Rate limits.
Cross-border VAT (tax_treatment)
An invoice carries a tax_treatment that controls its VAT treatment:
standard— normal Dutch BTW (the default).reverse_charge_eu— EU B2B reverse charge (btw verlegd).out_of_scope_non_eu_service— a service to a non-EU business, outside the scope of Dutch BTW.export_non_eu_goods— a 0% export of physical goods to a destination outside the EU (rubriek 3a). Goods lines only — a line classified as a service is rejected. Issuing creates a pending export-evidence record; the BTW filing stays blocked until the evidence (customs export declaration, transport documents) is verified in the Billey UI.
Send it on create or update; when omitted it defaults to standard. The response also includes reverse_charge_applied, a derived compatibility boolean that is true exactly when tax_treatment is reverse_charge_eu — new integrations should read tax_treatment. Quotes carry the same field.
Update an invoice
PATCH /api/v1/invoices/{invoice} is a full replace, not a partial merge — resend every header field and the complete items array, and only while the invoice is a draft. This is the single most common integration mistake; read PATCH behaviour first.
Lifecycle transitions
Move an invoice through its states with these bodyless POSTs (no Idempotency-Key); an invalid transition returns 409:
send— email the invoice to the client and mark it Sent (the client must have an email address, else422).mark-sent— mark Sent without emailing, for when you deliver it through your own channel.mark-paid— transition Sent → Paid.revert-to-draft— Sent → Draft; a paid invoice, or one in a locked period, cannot be reverted (409).
Credit notes
POST /api/v1/invoices/{invoice}/credit-note creates a credit note against a sent invoice (which must not itself be a credit note). Credit-note totals are stored positive; the direction is carried by is_credit_note: true. It is a create, so it takes an Idempotency-Key.
Delete
DELETE /api/v1/invoices/{invoice} soft-deletes a draft invoice (409 otherwise) and returns 204.