---
title: "Stop an invoice recurrence"
method: DELETE
path: "/public-api/v1/invoices/{invoice_id}/recurrence"
tags: ["Invoices"]
---

# Stop an invoice recurrence

`DELETE /public-api/v1/invoices/{invoice_id}/recurrence`

## Request

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

Ends a recurring or subscription series in one call. No further invoices
are generated, and for a subscription your client's card is no longer
charged automatically — the same thing the Bonsai app does when you end a
billing cycle.

Nothing already issued is touched. An invoice that is outstanding stays
outstanding and still needs paying, and nothing is deleted.

Pass any invoice in the series; the schedule always lives on the most
recent one, and that is the invoice you get back. So the `id` in the
response is often not the `invoice_id` you sent.

Read the result from `recurrence_active`, which is `false` once a series
is stopped. `repeat_interval` keeps reporting the cadence the series ran
on, because a stopped series keeps its schedule so it can be started
again. `kind` still reads `recurring` when the series issued more than
one invoice, because the invoice remains part of that series and keeps
its `series_id` — the app shows this as a completed recurring invoice.
Only an invoice that had not repeated yet comes back as `single`.

Stopping a series that never repeated leaves a draft invoice behind, and
stopping a subscription also turns off the auto-send that issued it. Both
match the app.

There is nothing to undo here and the call is not repeatable: an invoice
with no live recurrence returns `422` rather than quietly doing nothing.
A series that issued more than one invoice reports that it was already
stopped; one that never repeated is a plain one-off afterwards, and
reports that it is not recurring.

If your access is limited to certain projects and the most recent invoice
in the series is not one you can reach, the call returns `422` and stops
nothing, rather than stopping the newest invoice you happen to see and
leaving the series running.

## Response `200`

The series was stopped. `data` is the invoice that carried the schedule.

- 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

- `401`: The access token is missing, expired or invalid.
- `403`: This token is not allowed to change invoices.
- `404`: No invoice with that id that this token can see.
- `422`: Nothing was stopped: the invoice is a one-off, the series was already stopped, or the most recent invoice in it is one this token cannot reach.
- `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)
