> ## Documentation Index
> Fetch the complete documentation index at: https://docs.horizonpay.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Void an Invoice (Open/Overdue) — Invoice AI REST API

> Cancel an open or overdue invoice while keeping its number in the audit trail. Optionally provide a reason; the void is permanent and irreversible.

Cancels an open or overdue invoice and moves it to `void` status. The invoice number is **kept on the record** — it is not recycled or reassigned to a future invoice. This is intentional: an auditor reviewing a consecutive series expects to find every number accounted for. A voided invoice with a reason is the correct audit artifact; a missing number is a red flag.

After voiding, `amount_due` drops to `0`, `voided_at` is set to the current server time, and the `invoice.voided` webhook event fires.

```http theme={null}
POST /api/v1/invoices/:id/void
```

**Base URL:** `https://invoice.horizonpay.co`

***

## Authentication

<ParamField header="Authorization" type="string" required>
  Bearer token in the form `Bearer inv_live_…`. The token must carry the `invoices:finalize` scope (finalizing and voiding are the two halves of controlling the invoice number series).
</ParamField>

<ParamField header="Idempotency-Key" type="string" required>
  A unique key (UUID or any string up to 255 characters) you generate per logical void operation. This endpoint **requires** the header — the request is rejected with `428` if it is absent.
</ParamField>

<ParamField header="Content-Type" type="string">
  `application/json`. Required when sending a body; may be omitted if the body is empty.
</ParamField>

***

## Path Parameters

<ParamField path="id" type="string" required>
  The invoice's public ID (`in_…`) or its UUID. The invoice must currently be in `open` or `overdue` status.
</ParamField>

***

## Body Parameters

<ParamField body="reason" type="string">
  Human-readable explanation for why the invoice is being voided (e.g. `"Duplicate invoice created in error"`, `"Customer requested cancellation"`, `"Incorrect amount — replacement invoice issued as INV/25-26/0043"`). Stored in `void_reason` and shown in the invoice timeline. Optional, but strongly recommended for audit purposes.
</ParamField>

***

## Request Example

```bash theme={null}
curl -X POST https://invoice.horizonpay.co/api/v1/invoices/in_01JABCDEFGHIJKLMNOPQRSTU01/void \
  -H "Authorization: Bearer inv_live_sk_1234abcd5678efgh" \
  -H "Idempotency-Key: 018e4c70-3f2a-7b8d-9c12-d4e5f6034567" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Incorrect line item amounts — replacement issued as INV/25-26/0043"
  }'
```

***

## Response Example

```json theme={null}
{
  "data": {
    "id": "in_01JABCDEFGHIJKLMNOPQRSTU01",
    "object": "invoice",
    "number": "INV/25-26/0042",
    "status": "void",
    "customer": "cus_01J9ZXMQR7P4KBN2VWTF3D6H8A",
    "currency": "USD",
    "collection_method": "send_invoice",
    "issue_date": "2025-06-01",
    "due_date": "2025-07-01",
    "description": "Website redesign — Phase 2",
    "footer": "Payment due within 30 days. Bank transfer preferred.",
    "subtotal": 700000,
    "discount": 50000,
    "taxable": 650000,
    "tax": 108000,
    "total": 758000,
    "amount_due": 0,
    "amount_in_words": "Seven thousand five hundred and eighty dollars",
    "public_url_token": "tok_share_a1b2c3d4e5f6",
    "finalized_at": "2025-06-01T09:00:00.000Z",
    "paid_at": null,
    "voided_at": "2025-06-10T16:45:00.000Z",
    "void_reason": "Incorrect line item amounts — replacement issued as INV/25-26/0043",
    "created": "2025-06-01T08:00:00.000Z",
    "updated": "2025-06-10T16:45:00.000Z"
  }
}
```

<Warning>
  **`Idempotency-Key` is required on this endpoint.** Voiding an invoice with a number is a legally significant, irreversible action. A retry without a key on an already-voided invoice returns `409 invalid_state`, but a race between two retries could fire two `invoice.voided` webhook deliveries. Always generate a fresh UUID per void operation and retain it for retries.
</Warning>

<Warning>
  **Paid invoices cannot be voided.** Once an invoice has been marked paid, reversing it requires a credit note — a separate document with its own number and audit trail. Credit notes are out of scope for v1. Attempting to void a paid invoice returns `409 invalid_state`.
</Warning>

<Note>
  Draft invoices do not need to be voided — they can be deleted with `DELETE /api/v1/invoices/:id` because they have no number. Void is only meaningful once a number has been assigned by finalization.
</Note>

<Note>
  The response does **not** include the `lines` field. The line items are unchanged by voiding and can be retrieved with [GET /api/v1/invoices/:id](/api-reference/invoices/retrieve) if needed.
</Note>

***

## Response Fields

<ResponseField name="data.id" type="string">
  Unique public identifier for the invoice, prefixed `in_`.
</ResponseField>

<ResponseField name="data.object" type="string">
  Always `"invoice"`.
</ResponseField>

<ResponseField name="data.number" type="string">
  The invoice number is **preserved** on the void record. It is never reassigned.
</ResponseField>

<ResponseField name="data.status" type="string">
  `"void"` after a successful void operation.
</ResponseField>

<ResponseField name="data.amount_due" type="integer">
  Always `0` after the invoice is voided.
</ResponseField>

<ResponseField name="data.voided_at" type="string">
  ISO 8601 datetime when the invoice was voided.
</ResponseField>

<ResponseField name="data.void_reason" type="string | null">
  The reason string you supplied, or `null` if none was provided.
</ResponseField>

<ResponseField name="data.paid_at" type="null">
  Always `null` — a voided invoice was never paid.
</ResponseField>

For all other fields, see the [Retrieve Invoice response fields](/api-reference/invoices/retrieve#response-fields).

***

## Error Codes

| HTTP Status | `code`                     | Meaning                                                                                                                |
| ----------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `401`       | `unauthorized`             | Missing or invalid `Authorization` header.                                                                             |
| `403`       | `forbidden`                | Token does not carry the `invoices:finalize` scope.                                                                    |
| `404`       | `not_found`                | No invoice with that ID exists, or it belongs to a different account.                                                  |
| `409`       | `invalid_state`            | Invoice is not in `open` or `overdue` status. Drafts must be deleted, not voided. Paid invoices require a credit note. |
| `428`       | `idempotency_key_required` | `Idempotency-Key` header was not sent.                                                                                 |
| `429`       | `rate_limited`             | Per-credential rate limit exceeded. Check the `Retry-After` response header.                                           |
