---
title: "Update an invoice"
method: PATCH
path: "/public-api/v1/invoices/{id}"
tags: ["Invoices"]
---

# Update an invoice

`PATCH /public-api/v1/invoices/{id}`

## Request

- Base URL: `https://app.hellobonsai.com`
- URL: `https://app.hellobonsai.com/public-api/v1/invoices/{id}`
- Auth: one of:
  - OAuth 2
    - Authorization code: `https://app.hellobonsai.com/oauth/authorize`
    - Token URL: `https://app.hellobonsai.com/oauth/token`
  - HTTP bearer

Updates an invoice. Every field is optional, and anything you leave out
keeps its current value.

Only four things can change here: who the invoice is addressed to, its
title, its currency and when it is due. The client company and the project
are fixed once the invoice exists, and line items have their own
endpoints.

An invoice that is `paid` or has a payment in progress cannot be edited at
all, and returns `403`.

## Path parameters

- `id` integer, required

## Request body

- object
  - `invoice` object, required
    - `contact_id` integer: Id of the contact to address the invoice to, which also refreshes the client name and email printed on it. Must be a contact at the invoice's existing client company.
    - `currency` string: Three-letter ISO 4217 currency code.
    - `title` string: Invoice title shown to the client.
    - `due` 'upon_receipt' | 'custom': When payment is due.
    - `due_date` string, date: The exact date payment is due. Required when `due` is `custom`, and must be left out when `due` is `upon_receipt`. Sending it on its own is treated as `custom`.

## Response `200`

The invoice was updated.

- object
  - `data` Invoice, required: A bill you send to a client for work on one project, with its line items.
    - `id` integer, required: Unique identifier for the invoice.
    - `invoice_number` string, nullable, required: Human-readable invoice reference, unique within your account. The list endpoint accepts it as `filter[invoice_number]`.
    - `title` string, nullable, required: Invoice title shown to the client.
    - `currency` string, required: Three-letter ISO 4217 currency code every amount on the invoice is expressed in.
    - `issued_date` string, date, nullable, required: Issue date printed on the invoice. Set when the invoice is created, so a draft has one too; `sent_date` says whether the client has received it.
    - `due_date` string, date, nullable, required: Date payment is due, or `null` when the invoice is payable on receipt.
    - `sent_date` string, date-time, nullable, required: When the invoice was sent to the client, by email or as a shared link, or `null` while it has not been sent. A `drafted` or `scheduled` invoice has none.
    - `project_id` integer, nullable, required: Id of the project the invoice bills.
    - `client_email` string, nullable, required: Email address the invoice is addressed to, captured from the client contact when the invoice was created.
    - `public_url_token` string, nullable, required: Token in the invoice's client-facing URL. Anyone holding that link can view and pay the invoice, so treat this value as a secret.
    - `created_at` string, date-time, required: When the invoice was created.
    - `total_amount` string, required: What the client owes, as a decimal string, after any discount and tax.
    - `discount_amount` string, nullable, required: Discount taken off the subtotal, as a decimal string, or `null` when there is none.
    - `status` 'new' | 'drafted' | 'scheduled' | 'outstanding' | 'overdue' | 'pending' | 'paid' | 'deleted', required: Where the invoice is in its lifecycle: - `new`, `drafted` — not sent to the client yet. - `scheduled` — queued to send automatically on a future date. - `outstanding` — sent and awaiting payment. - `overdue` — sent, unpaid and past `due_date`. - `pending` — a payment has started but has not settled. - `paid` — paid in full. - `deleted` — the invoice has been deleted. An invoice that is `paid` or `pending` can no longer be edited, and neither can its line items.
    - `due_date_option` 'upon_receipt' | 'after_x_days' | 'custom' | 'null', nullable, required: How `due_date` was arrived at: `upon_receipt`, `after_x_days` (a fixed number of days after the issue date) or `custom` (an explicit date).
    - `company_id` integer, nullable, required: Id of the company being invoiced, or `null` when the invoice is addressed to a client that is not a company record.
    - `client_name` string, nullable, required: Name the invoice is addressed to.
    - `subtotal` string, nullable, required: Sum of every line item, before discount and tax, as a decimal string.
    - `tax_amount` string, nullable, required: Total tax on the invoice, as a decimal string, whether it is charged on the whole invoice or per line item.
    - `kind` 'single' | 'recurring' | 'subscription' | 'bundled', required: How the invoice repeats: - `single` — a one-off invoice. Scheduling one to send later does not make it recurring; `status` reports that as `scheduled`. - `recurring` — reissued on `repeat_interval` until you stop it or `repeat_finish_date` arrives. - `subscription` — recurring, and charged automatically to the card the client has on file. - `bundled` — one of several invoices grouped to be sent and paid together. `bundled` is read-only: bundles are assembled in the Bonsai app from invoices that already exist, so it cannot be passed when creating one.
    - `repeat_interval` 'weekly' | 'every two weeks' | 'every four weeks' | 'monthly' | 'every two months' | 'quarterly' | 'every six months' | 'annually' | 'null', nullable, required: How often a `recurring` or `subscription` invoice is reissued, or `null` for a one-off. It records the cadence an invoice was issued under rather than whether its series still runs: stopping a series keeps the interval on every invoice so the series can be started again, including one stopped before it repeated, which then reads `kind` `single`. Only the last invoice a series issues on `repeat_finish_date` comes back `null`. Use `recurrence_active` to tell a running series from a stopped or finished one.
    - `repeat_finish_date` string, date, nullable, required: Date the series stops reissuing, or `null` for a one-off or a series that runs until you stop it. Only the newest invoice of a series carries it: each repeat hands the date on to the invoice it creates, so earlier invoices read `null` even when the series has an end. When the date falls a whole number of `repeat_interval`s after the issue date, the final invoice is issued on it; otherwise the series ends with the last repeat before it. Stopping a series keeps the date so the series can be started again.
    - `series_id` integer, nullable, required: Id of the first invoice of the series this one belongs to, the same for every invoice in it, so you can group them. `null` for an invoice that is not part of a series.
    - `recurrence_active` boolean, required: Whether the series this invoice belongs to still reissues. Unlike `kind` and `repeat_interval`, which describe the invoice, this describes the series, so every invoice in it reports the same answer and an already-issued one turns `false` once the series is stopped. It is `true` exactly when `DELETE /invoices/{invoice_id}/recurrence` has something to stop.
    - `url` string, required: Absolute link to the invoice in the Bonsai app. This is the contractor-facing view, not the client payment page — for that, use `public_url_token`.
    - `invoice_items` InvoiceItem[], required: The invoice's line items, in the order they appear on it.
      - `id` integer, required: Unique identifier for the line item.
      - `name` string, nullable, required: Line item name, as it appears on the invoice.
      - `description` string, nullable, required: Longer description shown beneath the name, or `null`.
      - `amount` string, nullable, required: Quantity billed, as a decimal string.
      - `rate` string, nullable, required: Price per unit, as a decimal string in the invoice currency.
      - `unit_type` 'flat' | 'per_hour' | 'per_day' | 'per_item' | 'per_word' | 'per_week' | 'per_month' | 'per_year' | 'per_quarter' | 'null', nullable, required: What the rate is charged per. Defaults to `flat`.
      - `total` string, required: `amount` multiplied by `rate`, rounded, as a decimal string.
  - `meta` Meta, required: Metadata returned alongside every single-resource response.
    - `request_id` string, required: Identifier for this request. Quote it when contacting support about a specific call.

## Other responses

- `400`: The request body is missing its `invoice` wrapper.
- `401`: The access token is missing, expired or invalid.
- `403`: This token is not allowed to edit invoices, or the invoice is paid or has a payment in progress and can no longer be changed.
- `404`: No invoice with that id that this token can see.
- `422`: `due` and `due_date` disagree, or `contact_id` is not a contact at the invoice's client company.
- `429`: Rate limit exceeded. Wait at least `Retry-After` seconds before trying again.

---

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