Invoiz API

Create draft invoices, credit notes and customers from your own systems — and optionally send them over Peppol or by email.

The Invoiz API is a small REST API over HTTPS. Requests and responses are JSON. Every document you create lands in your Invoiz account as a draft, tagged with an API badge, so you can review it before it goes out — unless you explicitly ask us to send it.

Building this with an AI coding agent? Copy a ready-made prompt with everything Claude, Cursor or your agent needs to start writing the integration.

Base URL

https://rzcbampaeqjrghtuzzyq.supabase.co/functions/v1/api
The API is available on the Pro and Business plans. Each key belongs to one company.

Authentication

Create an API key in Invoiz under Settings → API keys. The full key is shown once — store it somewhere safe; we only keep a hash. Send it on every request as a Bearer token:

Authorization: Bearer invz_sk_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Or, if you prefer, with the X-API-Key header. Keys can be revoked at any time from the same screen; a revoked key immediately returns 401.

Keep keys server-side. A key can create and send invoices on your behalf — never ship one in a browser or mobile app.

Conventions & errors

  • All request bodies are JSON; send Content-Type: application/json.
  • Every response has a boolean ok. Errors look like { "ok": false, "error": "…" }.
  • Amounts are numbers in the document currency (default EUR). Totals are computed for you from the line items.
  • Idempotency: pass a unique external_ref when creating a document. A repeated external_ref returns the existing document instead of creating a duplicate.
StatusMeaning
200 / 201Success
400Bad request — a field is missing or invalid
401Missing, invalid or revoked API key
402The company needs an active Pro or Business plan
404Resource not found
422Can’t send — company or customer isn’t send-ready (see Auto-send)
500Unexpected server error

Find a customer

Look up an existing customer by VAT number or email before creating one.

GET/customers?vat=BE0123456789
GET/customers?email=finance@acme.be

Response

{
  "ok": true,
  "found": true,
  "customer": {
    "id": "c1a2…",
    "name": "Acme BV",
    "vat_number": "BE0123456789",
    "emails": ["finance@acme.be"],
    "peppol_id": null
  }
}

When no match is found you get { "ok": true, "found": false, "customer": null }.

Create a customer

POST/customers

If a customer with the same VAT number or email already exists for your company, that one is returned instead of a duplicate.

FieldTypeNotes
namestringrequired to create
vat_numberstringoptional — needed for Peppol
enterprise_numberstringoptional
email / emailsstring / string[]optional — needed for email sending
peppol_scheme, peppol_idstringoptional — explicit Peppol endpoint
iban, bicstringoptional
addressobjectoptional{ street, postalCode, city, country }
curl "$BASE/customers" \
  -H "Authorization: Bearer $INVOIZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme BV",
    "vat_number": "BE0123456789",
    "email": "finance@acme.be",
    "address": { "street": "Havenlaan 1", "postalCode": "1000", "city": "Brussel", "country": "BE" }
  }'

Create a draft invoice

POST/invoices

Identify the customer one of three ways: pass customer_id, or a customer object matched by VAT/email, or a full customer object that is created if it doesn’t exist yet.

FieldTypeNotes
customer_idstringUse an existing customer…
customerobject…or match/create one inline (see above)
linesarrayrequired — see Line items
currencystringoptional — default EUR
issue_date, due_datestringoptionalYYYY-MM-DD
notestringoptional
buyer_referencestringoptional — customer PO / reference
external_refstringoptional — your ID, for idempotency
sendobjectoptionalauto-send

Request

curl "$BASE/invoices" \
  -H "Authorization: Bearer $INVOIZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": { "name": "Acme BV", "vat_number": "BE0123456789", "email": "finance@acme.be" },
    "issue_date": "2026-07-21",
    "due_date": "2026-08-20",
    "external_ref": "order-10432",
    "lines": [
      { "description": "Consulting — July", "quantity": 3, "unit_price": 750, "vat_category": "21" },
      { "description": "Hosting",            "quantity": 1, "unit_price": 40,  "vat_category": "21" }
    ]
  }'

Response

{
  "ok": true,
  "invoice": {
    "id": "9f2a…",
    "kind": "invoice",
    "status": "draft",
    "number": null,
    "total": 2770.90,
    "currency": "EUR",
    "source": "api"
  },
  "customer_id": "c1a2…",
  "customer_created": true,
  "send": {}
}
Drafts have no invoice number yet — a gap-free legal number is assigned only when the invoice is issued (i.e. when you send it, here or in the app).

Create a draft credit note

POST/credit-notes

Identical to creating an invoice, with one extra optional field. Amounts are entered as positive numbers.

FieldTypeNotes
credit_of_invoice_idstringoptional — the invoice this credits
curl "$BASE/credit-notes" \
  -H "Authorization: Bearer $INVOIZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "c1a2…",
    "credit_of_invoice_id": "9f2a…",
    "lines": [ { "description": "Refund — hosting", "quantity": 1, "unit_price": 40, "vat_category": "21" } ]
  }'

Get an invoice

GET/invoices/{id}

Fetch the current status of any invoice or credit note you created — handy for polling after an auto-send.

{
  "ok": true,
  "invoice": {
    "id": "9f2a…", "kind": "invoice",
    "status": "peppol_submitted", "number": "2026-0042",
    "total": 2770.90, "peppol_status": "submitted"
  }
}

Auto-send over Peppol / email

Add a send object to a create request to dispatch the document immediately instead of leaving it as a draft.

"send": { "peppol": true, "email": true }
  • peppol — issues the document and delivers it over the Peppol network. Requires your company to be Peppol-ready (valid VAT, address, IBAN/BIC) and the customer to be reachable on Peppol (a valid VAT/enterprise number or explicit peppol_id).
  • email — issues the document and emails a PDF to the customer. Requires at least one customer email.

The response includes a per-channel send result so you always know what happened:

{
  "ok": true,
  "invoice": { "status": "peppol_submitted", "number": "2026-0042" },
  "send": {
    "peppol": { "ok": true, "status": "peppol_submitted" },
    "email":  { "ok": true }
  }
}
If a channel can’t send (e.g. the customer isn’t on Peppol), the document is still created; that channel simply reports { "ok": false, "error": "…" }. Omit send to keep everything as a reviewable draft.

Line items & VAT codes

Each entry in lines accepts:

FieldTypeNotes
descriptionstringrequired
quantitynumberoptional — default 1
unit_pricenumberoptional — excl. VAT, default 0
vat_categorystringoptional — default "21" (see below)
vat_ratenumberoptional — override the rate explicitly
unitstringoptional — UN/ECE code, default "C62" (each)

VAT categories

CodeRateMeaning
21 / 12 / 621% / 12% / 6%Standard Belgian rates
00%Zero-rated
MC0%Reverse charge (medecontractant)
ICL / ICD0%Intra-community goods / services
EX0%Export outside the EU
KO0%Small-enterprise exemption (art. 56bis)

Full example

Create a customer if needed, raise an invoice, and send it over Peppol — in one call:

BASE="https://rzcbampaeqjrghtuzzyq.supabase.co/functions/v1/api"

curl "$BASE/invoices" \
  -H "Authorization: Bearer $INVOIZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "name": "Acme BV",
      "vat_number": "BE0123456789",
      "email": "finance@acme.be"
    },
    "due_date": "2026-08-20",
    "external_ref": "order-10432",
    "lines": [
      { "description": "Consulting — July", "quantity": 3, "unit_price": 750, "vat_category": "21" }
    ],
    "send": { "peppol": true }
  }'
Copied