# Invoice an order

> Check whether an order's invoice is managed for you, create an invoice and add its lines, read and change it, find invoices across orders, read the totals, and delete or download one.

Web page: https://developer.yoprint.com/guides/invoices/

**Read first:** [Invoices and payments](https://developer.yoprint.com/how-yoprint-works/invoices-and-payments.md), for what an invoice bills, Auto Invoice, and how an order's balance is worked out.

> **Caution: Auto Invoice orders refuse invoices you make**
>
> When `auto_invoice_managed` is `true` on the order, YoPrint keeps one invoice in step with the order itself. Creating an invoice yourself is refused, and on that invoice you can't change a line's quantity, price or tax: change the sales order line instead, and the invoice follows.

An invoice bills some of a sales order's lines, with shipping fees, a discount or two, and a tax line of its own. This guide creates one, adds and edits its lines, reads it back across orders, and deletes or downloads it. It doesn't record payments: see [Record a payment](https://developer.yoprint.com/guides/payments.md).

**Diagram:** Check auto_invoice_managed before step 2: an Auto Invoice order refuses invoices you create yourself.

- **1. Check for Auto Invoice**: A managed order keeps its own invoice and won't take one you create
- **2. Create an invoice**: Starts from the order's addresses and issue date
- **3. Add its lines**: Billed order lines, shipping fees, discounts and tax
- **4. Read and change it**: Edit lines, header and tax, except the lines Auto Invoice manages
- **5. Find it across orders**: Filter your team's invoices, or list one order's
- **6. Read the totals**: What's billed, discounted, taxed and owed
- **7. Delete or download it**: Deleting frees its payments. Exporting makes a PDF

## 1. Check for Auto Invoice

`GET /v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}` [Get a sales order or quote](https://developer.yoprint.com/reference/sales-orders/v2-order-show.md)

Read the order's `auto_invoice_managed` field before you invoice it by hand.

- `true`: YoPrint maintains a single invoice itself, adding and updating lines as you change the order's lines and shipping fees.
- Creating an invoice yourself on that order is refused with `422` "You cannot create an invoice for an auto managed order."
- On the managed invoice, you can't add, edit or delete its order lines, or edit or delete the shipping fees and discounts YoPrint added. You can still add your own discounts and shipping fees.

To invoice by hand, turn Auto Invoice off first with the `configure_order_auto_invoice_managed` action:

`PUT /v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/action/{action_name}` [Run an action on a sales order or quote](https://developer.yoprint.com/reference/sales-orders/v2-order-single-action.md)

```bash
curl -X PUT https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7/action/configure_order_auto_invoice_managed \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "X-Yoprint-Decimal-Format: exact-v1" \
  -H "Content-Type: application/json" \
  -d '{ "auto_invoice_managed": false, "auto_invoice_shipment_price_type": "DONOTMANAGE", "auto_invoice_shipment_rate": { "value": 0, "dp": 0 } }'
```

All three fields are required. Turning it off leaves the invoices and their lines as they are. They stop being managed.

## 2. Create an invoice

`POST /v2/api/store/{team_slug}/v2/sales_order/{unique_key}/invoice` [Create an invoice for a sales order](https://developer.yoprint.com/reference/invoices/v2-sales-order-invoice-create.md)

```bash
curl https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7/invoice \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "X-Yoprint-Decimal-Format: exact-v1" \
  -H "Content-Type: application/json" \
  -d '{ "issue_date": "2026-11-03T00:00:00Z" }'
```

- Send `{}` for an empty invoice. Every field is optional: without `billing_address_id`, `shipping_address_id` or `issue_date`, the invoice takes the order's own.
- It gets the team's next invoice number. The answer's `data.id` is the invoice id. Keep it for every later step.
- Add lines in the same call with `item_actions`, in the same shape as the bulk operation in the next step, or add them afterward.
- Refused for a Shopify-synced order ("Cannot create invoice for a Shopify-synced order.") and for an order with Auto Invoice turned on (step 1).

## 3. Add its lines

`POST /v2/api/store/{team_slug}/v2/invoice/{unique_key}/item` [Add a line to an invoice](https://developer.yoprint.com/reference/invoice-line-items/v2-invoice-item-create.md)

Four kinds of line, by `product.type`:

| `product.type`                           | What it bills                                      |
| ---------------------------------------- | -------------------------------------------------- |
| `order_item`                             | One of the order's lines, by the order line's `id` |
| `shipment_fee`                           | A shipping charge, with its own price              |
| `invoice_discount`                       | A discount, as a percent or a fixed amount         |
| `user_tax`, `override_tax` or `auto_tax` | The invoice's one tax line (see step 4)            |

An order line's `id` is `data.item.id` in the answer that added it, or `id` in the order's `items` when you read the order. The answer here wraps the new invoice line the same way: its id is `data.item.id`.

A billed order line:

```json
{
  "product": { "type": "order_item", "properties": { "id": "ZJTJ2uF5dMiArL" } },
  "quantity": { "type": "unit", "total": { "value": 24, "dp": 0 } },
  "tax": { "type": "taxable" },
  "position": 100
}
```

A shipping fee:

```json
{
  "product": { "type": "shipment_fee", "properties": { "name": "Shipping", "shipping_taxable": false } },
  "pricing": { "type": "fee", "product": { "total": { "value": 1500, "dp": 2 } } },
  "position": 900
}
```

A discount:

```json
{
  "product": { "type": "invoice_discount", "properties": { "type": "percent", "rate": { "value": 10, "dp": 0 }, "applies_to_shipping": false, "name": "Loyalty discount" } },
  "position": 950
}
```

The tax line, from a tax preset:

```json
{
  "product": { "type": "user_tax", "properties": { "id": "KC48n7qAAfGYMM" } },
  "position": 1000
}
```

- One invoice can't bill the same order line twice: a second time is `422` "Invoice already has the same Order Item".
- You can bill fewer than was ordered (the order line shows "partly" invoiced) or more (it shows "over-invoiced"). The quantity can't be negative.
- An invoice holds at most one tax line. To switch kinds, use [Change the tax](#change-the-tax) instead of creating a second line.

To add, change and remove several lines in one save:

`POST /v2/api/store/{team_slug}/v2/invoice/{unique_key}/item/bulk` [Add, change and remove invoice lines at once](https://developer.yoprint.com/reference/invoice-line-items/v2-invoice-item-bulk.md)

```json
[
  { "bid": "row-1", "action": "create", "payload": { "product": { "type": "order_item", "properties": { "id": "ZJTJ2uF5dMiArL" } }, "quantity": { "type": "unit", "total": { "value": 24, "dp": 0 } }, "position": 100 } },
  { "bid": "row-2", "action": "update", "cart_item_id": "wigm2YNiE4PciF", "payload": { "quantity": { "type": "unit", "total": { "value": 6, "dp": 0 } } } },
  { "bid": "row-3", "action": "delete", "cart_item_id": "DW7m2sWa8vVVDL" }
]
```

- Runs every delete, then every create, then every update, then recalculates once: all saved, or none.
- Tax lines can't be added or changed here: `422` "Tax Item is not allow in bulk operations."

## 4. Read and change an invoice

`GET /v2/api/store/{team_slug}/v2/invoice/{unique_key}` [Get an invoice](https://developer.yoprint.com/reference/invoices/v2-invoice-show.md)

`GET /v2/api/store/{team_slug}/v2/invoice/{unique_key}/item` [List the lines of an invoice](https://developer.yoprint.com/reference/invoice-line-items/v2-invoice-item-index.md)

- Get an invoice returns its header, lines under `items`, and its `order`. Send `X-Yoprint-Decimal-Format: exact-v1` so large totals come back exact. See [Money and quantities](https://developer.yoprint.com/concepts/money-and-quantities.md).
- List the lines returns them unsorted: sort by `position` yourself.

To change the header, its lines and its tax together:

`PUT /v2/api/store/{team_slug}/v2/invoice/{unique_key}` [Update an invoice](https://developer.yoprint.com/reference/invoices/v2-invoice-update.md)

```json
{
  "issue_date": "2026-11-03T00:00:00Z",
  "item_actions": [
    { "bid": "row-1", "action": "create", "payload": { "product": { "type": "order_item", "properties": { "id": "ZJTJ2uF5dMiArL" } }, "quantity": { "type": "unit", "total": { "value": 24, "dp": 0 } }, "position": 100 } }
  ],
  "tax_selection": { "expected_tax": null, "desired_tax": { "type": "user_tax", "properties": { "id": "KC48n7qAAfGYMM" } } },
  "resort_items": false
}
```

- Everything saves together or not at all. `item_actions` can delete the tax line, except on an Auto Invoice invoice, but can't create or change it: use `tax_selection` for that.
- There's no locked or permanently paid state: you can edit a paid invoice, and YoPrint redistributes (reallocates) the order's recorded payments across its invoices to match.

Or change one line at a time:

`PUT /v2/api/store/{team_slug}/v2/invoice/item/{unique_key}` [Update an invoice line](https://developer.yoprint.com/reference/invoice-line-items/v2-invoice-item-update.md)

```json
{ "quantity": { "type": "unit", "total": { "value": 12, "dp": 0 } }, "lock_version": 1730000000000000 }
```

- Send only what you change. A line's kind can't change.
- `lock_version` is the value from when you read the line. Someone else's save since then is `422` `optimistic_lock_conflict`.

`DELETE /v2/api/store/{team_slug}/v2/invoice/item/{unique_key}` [Remove a line from an invoice](https://developer.yoprint.com/reference/invoice-line-items/v2-invoice-item-destroy.md)

- On an Auto Invoice invoice you can't remove its order lines, shipping fees or discounts: "You cannot delete order Item for an auto managed invoice."

### Change the tax

`PUT /v2/api/store/{team_slug}/v2/invoice/{unique_key}/tax-selection` [Change the tax on an invoice](https://developer.yoprint.com/reference/invoices/v2-invoice-tax-selection-update.md)

```json
{
  "expected_tax": { "id": "WzHB84GM5mzqAw", "lock_version": 1730000000000001 },
  "desired_tax": { "type": "override_tax", "properties": { "mode": "tax_exempt", "total": { "value": 0, "dp": 0 } } }
}
```

- `expected_tax` is the tax line you think is there now (its `id` and `lock_version`, or `null` when there's none). A mismatch changes nothing: `422` `invoice_tax_conflict`.
- `desired_tax` is what you want, or `null` to remove the tax line. A different `type` from the current one replaces the line. The same `type` updates it.
- Setting a tax line makes it yours: YoPrint stops managing it, even on an Auto Invoice invoice.

## 5. Find invoices across orders

`POST /v2/api/store/{team_slug}/v2/invoice/filter` [Filter invoices](https://developer.yoprint.com/reference/invoices/v2-invoice-filter.md)

```json
{
  "filters": [
    { "key": "payment_status", "operator": "eq", "value": "unpaid" },
    { "key": "quote", "operator": "eq", "value": false }
  ],
  "sort": [{ "key": "full_amount_due", "direction": "asc" }]
}
```

- Filters: `payment_status` (`paid`, `unpaid` or `overdue`), `quote`, `order_status_id`, `order_customer_id`, `external_type`, and dates.
- The date filters read the invoice's order: `order_issue_date`, `order_cust_due_date`, `order_ship_due_date`, `deposit_due` and `full_amount_due`. Each takes a whole number of days from today, and compares whole UTC days, day N included: `{ "key": "full_amount_due", "operator": "lte", "value": 7 }` finds invoices whose order's full amount is due by the end of the 7th UTC day from today, overdue ones included. The invoice's own `created_at` leaves day N out, like the other v2 filters. See [Filtering and sorting](https://developer.yoprint.com/concepts/filtering-and-sorting.md#dates-are-days-from-today-and-v1-and-v2-count-differently).
- Needs Manage Sales Orders view access. Other roles get `403`.

To list one order's invoices instead:

`GET /v2/api/store/{team_slug}/v2/sales_order/{unique_key}/invoice` [List the invoices of a sales order](https://developer.yoprint.com/reference/invoices/v2-sales-order-invoice-index-for-order.md)

- The path's `{unique_key}` takes the order's `id` only. Send the order's own `unique_key` string instead and the list comes back empty, not an error.
- An id that isn't one of your orders also returns an empty list.

## 6. Read the totals

| On the invoice       | What it is                                                                                                                  |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `cart_item_subtotal` | Billed lines and shipping fees, before discounts and tax. `shipment_subtotal` is the shipping part of it, already included. |
| `discount_subtotal`  | Discounts on the invoice.                                                                                                   |
| `tax_subtotal`       | Tax on the invoice.                                                                                                         |
| `total`              | `cart_item_subtotal` − `discount_subtotal` + `tax_subtotal` (plus a card surcharge, when there is one).                     |

They're decimal pairs at `dp` 4: read `dp` every time. See [Money and quantities](https://developer.yoprint.com/concepts/money-and-quantities.md).

On the order, once invoices exist:

| On the order        | What it is                                |
| ------------------- | ----------------------------------------- |
| `invoiced_total`    | What's been billed, across every invoice. |
| `order_balance_due` | `invoiced_total` minus what's been paid.  |

See [How the balance works](https://developer.yoprint.com/how-yoprint-works/invoices-and-payments.md#how-the-balance-works) for how YoPrint gets from the order's lines to what the customer owes.

## 7. Delete or download an invoice

`DELETE /v2/api/store/{team_slug}/v2/invoice/{unique_key}` [Delete an invoice](https://developer.yoprint.com/reference/invoices/v2-invoice-destroy.md)

- Deletes the invoice and its lines. Its payments stay on the order: the amounts allocated to this invoice are redistributed across the order's other invoices, or returned to unallocated balance.
- Refused for an Auto Invoice invoice ("You cannot delete an auto managed invoice.") and for one synced from Shopify.
- Deleting an invoice that's already deleted succeeds and changes nothing.

Download one or more invoices as a PDF:

`POST /v1/api/store/{team_slug}/invoice/export_pdf` [Download invoices as one PDF](https://developer.yoprint.com/reference/invoices/v1-invoice-export-pdf.md)

```bash
curl https://secure.yoprint.com/v1/api/store/your-team/invoice/export_pdf \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "X-Yoprint-Decimal-Format: exact-v1" \
  -H "Content-Type: application/json" \
  -d '{ "invoice": [{ "id": "cBRpSf5nw6upt5" }, { "id": "gtnwEWU4Npp9eC" }] }'
```

- 1 to 100 invoices per call, combined into one PDF made while you wait. Nothing is stored.
- An id that isn't your team's is skipped without an error: check your ids first, or you can get back an empty PDF rather than a failure.
- Each invoice also carries its own link in `pdf_url` (from Get an invoice or the order's invoice list), with its own long-lived access token: don't publish it.

## Pitfalls

- **Invoice creates aren't idempotent.** There's no `operation_key`. If a create times out, list the order's invoices (step 5) before retrying. See [Retries and duplicates](https://developer.yoprint.com/concepts/retries-and-duplicates.md).
- **There are no invoice webhooks or events.** Read the order or invoice again, or poll on a schedule, to follow a change.
- **The bulk line operation skips the `lock_version` check.** Unlike the single update, a bulk `update` can silently overwrite someone else's edit.
- **`is_valid: false` means the invoice needs fixing**, even though the save succeeded: no lines, lines with no tax line, or a customer that doesn't match the order's.
- **Changing only the addresses on a manual invoice doesn't recalculate its tax.** Send `tax_selection` in the same [Update an invoice](#4-read-and-change-an-invoice) call to redo tax for the new address.
- **A discount's amount comes back as `total`, though you send it as `rate`.**
