> ## 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.

# Invoice Items API — List, Create, Retrieve, and Delete

> Add and remove line items on draft invoices. Reference a catalog price or supply a custom description and unit amount. All amounts are integer minor units.

# Invoice Items

An **invoice item** (`invoiceitem`) is a single line on an invoice. Items can either reference a catalog [price](/api-reference/prices/overview) — inheriting its unit amount, currency, and tax rate — or be fully ad-hoc with an explicit description and `unit_amount`.

Invoice items can only be added to or removed from **draft** invoices. Finalized invoices are locked and cannot be mutated.

**All monetary amounts are integers in minor currency units.** For USD, `10000` = \$100.00.

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

***

## The invoice item object

```json theme={null}
{
  "id": "ii_01hxyz1234567890abcdefghij",
  "object": "invoiceitem",
  "price": "price_01hxyz1234567890abcdefghij",
  "product": "prod_01hxyz1234567890abcdefghij",
  "description": "Professional Consulting",
  "quantity": 3,
  "unit": "HRS",
  "unit_amount": 15000,
  "amount": 42525,
  "discount_percent": 5,
  "tax_rate": 10,
  "tax_amount": 4253
}
```

<ResponseField name="id" type="string">
  Unique identifier for the invoice item. Prefixed with `ii_`.
</ResponseField>

<ResponseField name="object" type="string">
  String literal `"invoiceitem"`.
</ResponseField>

<ResponseField name="price" type="string | null">
  The `price_`-prefixed ID of the catalog price this item references. `null` for ad-hoc lines.
</ResponseField>

<ResponseField name="product" type="string | null">
  The `prod_`-prefixed ID of the parent product. Populated automatically when `price` is set. `null` for ad-hoc lines.
</ResponseField>

<ResponseField name="description" type="string">
  Description shown on the invoice. Inherited from the product name when a price is referenced, unless overridden.
</ResponseField>

<ResponseField name="quantity" type="number">
  Number of units billed. Must be greater than zero.
</ResponseField>

<ResponseField name="unit" type="string">
  Unit of measure code. One of: `NOS`, `PCS`, `KGS`, `GMS`, `LTR`, `MTR`, `SQF`, `SQM`, `HRS`, `DAY`, `MON`, `BOX`, `SET`, `OTH`.
</ResponseField>

<ResponseField name="unit_amount" type="integer">
  Unit price in minor currency units. For priced lines, this is taken from the referenced price.
</ResponseField>

<ResponseField name="amount" type="integer">
  Line total in minor units, after discount and before tax: `unit_amount × quantity × (1 − discount_percent / 100)`.
</ResponseField>

<ResponseField name="discount_percent" type="number">
  Discount percentage applied to this line. Range: `0`–`100`. Defaults to `0`.
</ResponseField>

<ResponseField name="tax_rate" type="number">
  Tax rate percentage applied to this line. Inherited from the price when a price is referenced.
</ResponseField>

<ResponseField name="tax_amount" type="integer">
  Tax amount in minor units: `amount × tax_rate / 100`, rounded.
</ResponseField>

***

## Endpoints

<AccordionGroup>
  <Accordion title="GET /api/v1/invoice-items?invoice= — List items on an invoice">
    List all line items belonging to a specific invoice. The `invoice` query parameter is **required**.

    **Required scope:** `invoices:read`

    ### Query parameters

    <ParamField query="invoice" type="string" required>
      The `in_`-prefixed invoice ID or UUID whose line items you want to retrieve.
    </ParamField>

    ### Request

    ```bash theme={null}
    curl "https://invoice.horizonpay.co/api/v1/invoice-items?invoice=in_01hxyz1234567890abcdefghij" \
      -H "Authorization: Bearer inv_live_..."
    ```

    ### Response

    ```json theme={null}
    {
      "data": [
        {
          "id": "ii_01hxyz1234567890abcdefghij",
          "object": "invoiceitem",
          "price": "price_01hxyz1234567890abcdefghij",
          "product": "prod_01hxyz1234567890abcdefghij",
          "description": "Professional Consulting",
          "quantity": 3,
          "unit": "HRS",
          "unit_amount": 15000,
          "amount": 42525,
          "discount_percent": 5,
          "tax_rate": 10,
          "tax_amount": 4253
        },
        {
          "id": "ii_01hxyz9876543210zyxwvutsrq",
          "object": "invoiceitem",
          "price": null,
          "product": null,
          "description": "Travel reimbursement",
          "quantity": 1,
          "unit": "OTH",
          "unit_amount": 32500,
          "amount": 32500,
          "discount_percent": 0,
          "tax_rate": 0,
          "tax_amount": 0
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="POST /api/v1/invoice-items — Add a line item">
    Append one line item to a draft invoice. You may reference a catalog price **or** supply an ad-hoc description and unit amount — not both.

    **Required scope:** `invoices:write`

    **Idempotency-Key is required** for this endpoint. Duplicate requests with the same key will return the same item without creating a second line.

    ### Priced lines vs. ad-hoc lines

    |                 | Priced line                 | Ad-hoc line                             |
    | --------------- | --------------------------- | --------------------------------------- |
    | Required fields | `invoice`, `price`          | `invoice`, `description`, `unit_amount` |
    | `unit_amount`   | Inherited from price        | You supply it in minor units            |
    | `tax_rate`      | Inherited from price        | Defaults to `0`; you may override       |
    | `description`   | Inherited from product name | You supply it                           |

    ### Body parameters

    <ParamField body="invoice" type="string" required>
      The `in_`-prefixed ID or UUID of the draft invoice to append the item to.
    </ParamField>

    <ParamField body="price" type="string">
      The `price_`-prefixed ID of a catalog price. When present, `unit_amount`, `tax_rate`, and `description` are inherited from the price and its product unless you explicitly override them.
    </ParamField>

    <ParamField body="description" type="string">
      Line-item description. Required for ad-hoc lines (when `price` is omitted). Defaults to `""`.
    </ParamField>

    <ParamField body="quantity" type="number">
      Number of units. Must be greater than `0`. Defaults to `1`.
    </ParamField>

    <ParamField body="unit" type="string">
      Unit of measure. One of: `NOS`, `PCS`, `KGS`, `GMS`, `LTR`, `MTR`, `SQF`, `SQM`, `HRS`, `DAY`, `MON`, `BOX`, `SET`, `OTH`. Defaults to `NOS`.
    </ParamField>

    <ParamField body="unit_amount" type="integer">
      Unit price in minor currency units. Required for ad-hoc lines. Omit to use the price's amount.
    </ParamField>

    <ParamField body="discount_percent" type="number">
      Discount percentage for this line only. Range: `0`–`100`. Defaults to `0`.
    </ParamField>

    <ParamField body="tax_rate" type="number">
      Tax rate percentage. Range: `0`–`100`. Omit to inherit from the price.
    </ParamField>

    ### Request — priced line

    ```bash theme={null}
    curl https://invoice.horizonpay.co/api/v1/invoice-items \
      -X POST \
      -H "Authorization: Bearer inv_live_..." \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: add-line-inv123-price456" \
      -d '{
        "invoice": "in_01hxyz1234567890abcdefghij",
        "price": "price_01hxyz1234567890abcdefghij",
        "quantity": 3,
        "unit": "HRS",
        "discount_percent": 5
      }'
    ```

    ### Request — ad-hoc line

    ```bash theme={null}
    curl https://invoice.horizonpay.co/api/v1/invoice-items \
      -X POST \
      -H "Authorization: Bearer inv_live_..." \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: add-line-inv123-travel" \
      -d '{
        "invoice": "in_01hxyz1234567890abcdefghij",
        "description": "Travel reimbursement",
        "quantity": 1,
        "unit": "OTH",
        "unit_amount": 32500
      }'
    ```

    ### Response `201 Created`

    The response envelope contains the **full updated invoice object** (with all line items and recomputed totals), not just the newly created item.

    ```json theme={null}
    {
      "data": {
        "id": "in_01hxyz1234567890abcdefghij",
        "object": "invoice",
        "number": null,
        "status": "draft",
        "customer": "cus_01hxyz1234567890abcdefghij",
        "currency": "USD",
        "subtotal": 75025,
        "discount": 3750,
        "taxable": 71275,
        "tax": 4253,
        "total": 75528,
        "amount_due": 0,
        "lines": {
          "data": [
            {
              "id": "ii_01hxyz1234567890abcdefghij",
              "object": "invoiceitem",
              "price": "price_01hxyz1234567890abcdefghij",
              "product": "prod_01hxyz1234567890abcdefghij",
              "description": "Professional Consulting",
              "quantity": 3,
              "unit": "HRS",
              "unit_amount": 15000,
              "amount": 42525,
              "discount_percent": 5,
              "tax_rate": 10,
              "tax_amount": 4253
            },
            {
              "id": "ii_01hxyz9876543210zyxwvutsrq",
              "object": "invoiceitem",
              "price": null,
              "product": null,
              "description": "Travel reimbursement",
              "quantity": 1,
              "unit": "OTH",
              "unit_amount": 32500,
              "amount": 32500,
              "discount_percent": 0,
              "tax_rate": 0,
              "tax_amount": 0
            }
          ]
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="GET /api/v1/invoice-items/:id — Retrieve an item">
    Retrieve a single invoice item by its `ii_`-prefixed ID.

    **Required scope:** `invoices:read`

    The `:id` path parameter accepts either the `ii_`-prefixed public ID or the underlying UUID.

    ### Request

    ```bash theme={null}
    curl https://invoice.horizonpay.co/api/v1/invoice-items/ii_01hxyz1234567890abcdefghij \
      -H "Authorization: Bearer inv_live_..."
    ```

    ### Response `200 OK`

    ```json theme={null}
    {
      "data": {
        "id": "ii_01hxyz1234567890abcdefghij",
        "object": "invoiceitem",
        "price": "price_01hxyz1234567890abcdefghij",
        "product": "prod_01hxyz1234567890abcdefghij",
        "description": "Professional Consulting",
        "quantity": 3,
        "unit": "HRS",
        "unit_amount": 15000,
        "amount": 42525,
        "discount_percent": 5,
        "tax_rate": 10,
        "tax_amount": 4253
      }
    }
    ```
  </Accordion>

  <Accordion title="DELETE /api/v1/invoice-items/:id — Remove an item">
    Remove a line item from a draft invoice. The invoice's totals are immediately recomputed.

    **Required scope:** `invoices:write`

    You may optionally pass `?invoice=in_…` as a query parameter to scope the lookup to a specific invoice. Without it, all invoices in your workspace are searched.

    ### Request

    ```bash theme={null}
    curl "https://invoice.horizonpay.co/api/v1/invoice-items/ii_01hxyz1234567890abcdefghij?invoice=in_01hxyz1234567890abcdefghij" \
      -X DELETE \
      -H "Authorization: Bearer inv_live_..."
    ```

    ### Response `200 OK`

    The response contains the **full updated invoice** with the item removed and totals recomputed.

    ```json theme={null}
    {
      "data": {
        "id": "in_01hxyz1234567890abcdefghij",
        "object": "invoice",
        "number": null,
        "status": "draft",
        "customer": "cus_01hxyz1234567890abcdefghij",
        "currency": "USD",
        "subtotal": 32500,
        "discount": 0,
        "taxable": 32500,
        "tax": 0,
        "total": 32500,
        "amount_due": 0,
        "lines": {
          "data": [
            {
              "id": "ii_01hxyz9876543210zyxwvutsrq",
              "object": "invoiceitem",
              "price": null,
              "product": null,
              "description": "Travel reimbursement",
              "quantity": 1,
              "unit": "OTH",
              "unit_amount": 32500,
              "amount": 32500,
              "discount_percent": 0,
              "tax_rate": 0,
              "tax_amount": 0
            }
          ]
        }
      }
    }
    ```
  </Accordion>
</AccordionGroup>

***

## Supported unit codes

| Code  | Meaning                         |
| ----- | ------------------------------- |
| `NOS` | Numbers / items (generic count) |
| `PCS` | Pieces                          |
| `KGS` | Kilograms                       |
| `GMS` | Grams                           |
| `LTR` | Litres                          |
| `MTR` | Metres                          |
| `SQF` | Square feet                     |
| `SQM` | Square metres                   |
| `HRS` | Hours                           |
| `DAY` | Days                            |
| `MON` | Months                          |
| `BOX` | Box                             |
| `SET` | Set                             |
| `OTH` | Other                           |

***

## Error responses

| Status             | Cause                                                                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`  | Missing `invoice` on list/create; missing `description` + `unit_amount` on ad-hoc create; non-integer `unit_amount`; or invoice is not in draft status. |
| `401 Unauthorized` | Missing or invalid `Authorization` header.                                                                                                              |
| `403 Forbidden`    | The API key lacks `invoices:read` or `invoices:write`.                                                                                                  |
| `404 Not Found`    | No item or invoice with the given ID exists in your workspace.                                                                                          |
| `409 Conflict`     | An `Idempotency-Key` was reused with a different request body.                                                                                          |
