---
title: "Update an invoice"
method: PUT
path: "/invoices/{id}"
tags: ["Invoices"]
---

# Update an invoice

`PUT /invoices/{id}`

## Request

- Base URL: `https://api.lumabill.ch/v1`
- URL: `https://api.lumabill.ch/v1/invoices/{id}`
- Auth: HTTP bearer

Partial update: fields omitted from the body keep their stored values (invoice number, dates, client, sender, payment, currency, attachments, ...). Only invoices in `draft` status can be fully updated. Changing the `status` field moves the invoice through its lifecycle; status values are case-insensitive. The currency and the rate of an issued or paid invoice, credit note or offer are locked: a different `currency` or `exchangeRate` answers 400 CURRENCY_LOCKED (cancel and re-issue instead; before 3.14.0 a different `exchangeRate` was silently ignored). An unsupported `currency` answers 400 UNSUPPORTED_CURRENCY (with `currency`). A foreign-currency invoice in a fiscal year with a booked FX revaluation refuses a change of its total or date with 400 FX_REVALUATION_LIVE (re-run the revaluation after a cancel and re-issue instead).

## Request body

- InvoiceWrite
  - `invoice_number` string, nullable: Explicit number (imports, own numbering schemes), stored as given also on a draft; 409 DUPLICATE_INVOICE_NUMBER when another document of the same type in the profile already uses it. If omitted, a draft stays unnumbered and the next number from the profile prefix + counter (e.g. `IV-010`) is assigned when the document is issued (status leaves draft, or it is emailed). null clears the number of a never-issued draft; an issued document keeps its number.
  - `client_id` string, uuid: UUID of an existing client. The API fetches the client data and snapshots it on the invoice. Returns `404` if not found.
  - `status` 'draft' | 'sent'
  - `issue_date` string, date: Defaults to today if omitted.
  - `due_date` string, date: Defaults to `issue_date` + profile payment deadline days (default 30) if omitted.
  - `currency` 'CHF' | 'EUR' | 'USD' | 'GBP' | 'JPY' | 'CAD' | 'AUD' | 'SEK' | 'NOK' | 'DKK' | 'HUF': ISO 4217 code of a currency the API converts (ESTV/BAZG rates). The same list applies to every currency field of the API.
  - `exchangeRate` number, double, nullable: Foreign-currency invoice only: CHF per 1 unit of `currency`, stored as a manual rate (MWSTV 45 Abs. 3bis). Omit to use the ESTV/BAZG rate of the invoice date. Taken while the invoice is a draft or by the write that issues it; an issued invoice keeps its rate. Issuing a foreign-currency invoice without any rate (e.g. dated in a Monatsmittel month that has not started) is refused with 400 FX_RATE_UNAVAILABLE; when ESTV/BAZG cannot be reached and no rate is cached the write answers 400 FX_RATE_SOURCE_UNAVAILABLE (retry later, it is not a missing rate); 400 INVALID_EXCHANGE_RATE when not a positive number, 400 EXCHANGE_RATE_IMPLAUSIBLE when outside 0.5x to 2x of the ESTV/BAZG rate of the date (0.0001 to 100 without one; the body carries `officialRate`, `min`, `max`). `null` is the same as omitting it (unlike the expense and revenue update, it does not drop a stored manual rate).
  - `lines` InvoiceLine[], required
    - `description` string, required
    - `quantity` number, double, required
    - `price` number, double, required
    - `vat_rate` number, double, nullable: VAT rate as a percentage (e.g. 8.1 for 8.1 %). If omitted, the profile's default tax rate is used.
  - `notes` string, nullable
  - `payment_terms` string, nullable

## Response `200`

Updated invoice

- Invoice
  - `id` string, uuid, required
  - `invoice_number` string, nullable, required: null while the document is an unnumbered draft. Numbers are assigned when the document is first issued (leaves draft) and never removed afterwards.
  - `client_id` string, uuid, required
  - `status` 'draft' | 'sent' | 'paid' | 'overdue', required
  - `issue_date` string, date, required
  - `due_date` string, date, required
  - `total` number, double, required: Total invoice amount including VAT
  - `currency` 'CHF' | 'EUR' | 'USD' | 'GBP' | 'JPY' | 'CAD' | 'AUD' | 'SEK' | 'NOK' | 'DKK' | 'HUF', required: ISO 4217 code of a currency the API converts (ESTV/BAZG rates). The same list applies to every currency field of the API.
  - `lines` InvoiceLine[], required
    - `description` string, required
    - `quantity` number, double, required
    - `price` number, double, required
    - `vat_rate` number, double, nullable: VAT rate as a percentage (e.g. 8.1 for 8.1 %). If omitted, the profile's default tax rate is used.
  - `notes` string, nullable
  - `payment_terms` string, nullable
  - `created_at` string, date-time, required

## Other responses

- `400`: Validation error
- `401`: Invalid or missing API key
- `403`: Subscription required or read-only key on a write endpoint
- `404`: Resource not found
- `429`: Rate limit exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/lumabill/apis/lumabill-api.md) · [All operations](https://skmtc.dev/lumabill/apis/lumabill-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lumabill/apis/lumabill-api/revisions/e48e7099b545?raw)
