---
title: "List invoices"
method: GET
path: "/v1/invoices"
tags: ["Invoices"]
---

# List invoices

`GET /v1/invoices`

## Request

- Base URL: `https://api.officina.it`
- URL: `https://api.officina.it/v1/invoices`
- Auth: HTTP bearer

Returns invoices in the authenticated user's company, newest
first. Filter by name (`?q=`), payment state
(`?payment_filter=pending|settled`), fiscal status
(`?fiscal_status=draft|issued`), or date range
(`?from=`/`?to=`/`?preset=`). Paginate with cursor-based
`?limit=` + `?starting_after=`.

The date window defaults to the last 12 months; set it with
`from`/`to`/`preset`. The applied range is echoed in
`date_filter`.

The cursor is opaque — clients MUST NOT parse it. Pass back
the value verbatim. `has_more` drives the "load more" UI;
a full page may still be the last page.

List rows OMIT `line_items` to keep payloads small. Fetch
the detail endpoint for the full body.

## Query parameters

- `q` string
- `payment_filter` 'pending' | 'settled'
- `fiscal_status` 'draft' | 'issued'
- `sort` 'date' | 'number' | 'customer' | 'vehicle' | 'total' | 'outstanding'
- `direction` 'asc' | 'desc'
- `from` string, date
- `to` string, date
- `preset` 'rel30' | 'rel90' | 'rel365' | 'year' | 'Q1' | 'Q2' | 'Q3' | 'Q4' | 'month' | 'custom' | 'all'
- `limit` integer
- `starting_after` string
- `without_electronic_invoice` boolean

## Response `200`

Page of invoices (line_items omitted).

- object
  - `object` 'list', required: Polymorphic discriminator.
  - `data` Invoice[], required: Page of items. Each item carries its own `object` field.
    - `object` 'invoice', required
    - `id` string, required
    - `status` 'draft' | 'issued', required: Derived from `issued_at`. Soft-deleted invoices 404 before reaching the client — "deleted" is never emitted.
    - `title` string, nullable
    - `comments` string, nullable
    - `internal_comments` string, nullable
    - `payment_method` string, required
    - `payment_condition` string, required
    - `payment_due_at` string, date-time, required
    - `vat_exigibility` string, required
    - `sezionale_id` string, nullable
    - `pa_document_type` string, nullable
    - `pa_document_number` string, nullable
    - `pa_document_date` string, date-time, nullable
    - `pa_cig` string, nullable
    - `pa_cup` string, nullable
    - `customer_id` string, required
    - `vehicle_id` string, nullable
    - `worksheet_id` string, nullable
    - `seq_number` integer, required: Per-company monotonic invoice number. 0 on drafts; assigned atomically at issuance.
    - `total_before_tax` number, double, required: Money. Float64 — clients render via the workshop locale formatter; avoid arithmetic.
    - `total_tax` number, double, required
    - `total_after_tax` number, double, required
    - `total_discount` number, double, required
    - `total_after_discount` number, double, required
    - `total_payments` number, double, required
    - `outstanding_payments` number, double, required
    - `customer_name` string, required
    - `vehicle_name` string, nullable
    - `vehicle_license` string, nullable
    - `created_by_full_name` string, required
    - `sezionale_code` string, nullable
    - `work_category_name` string, nullable
    - `work_category_names` string[], required: Names of the linked worksheet's work categories, in order. `[]` when the invoice has no worksheet or the worksheet has none. `work_category_name` is the first one. Available since revision 2026-10-03.
    - `sdi_status` string, required: Italian SDI e-invoice lifecycle status. Empty string when no e-invoice exists for this invoice. Possible non-empty values: "sent", "rejected", "pending_normal", "pending_warning", "pending_late".
    - `created_at` string, date-time, required
    - `updated_at` string, date-time, required
    - `issued_at` string, date-time, nullable: Populated once the invoice is issued.
    - `deleted_at` string, date-time, nullable: Soft-deletion timestamp. Populated only on the response from DELETE /v1/invoices/{id}.
    - `line_items` InvoiceLineItem[]: Populated on detail and post-mutation responses. Omitted from list rows to keep payloads small.
      - `object` 'invoice_line_item', required
      - `id` string, required
      - `line_type` 'item' | 'note' | 'separator', required: `item` is a priced line. `note` is a description-only line and `separator` an empty spacer row: both print without quantity, price and VAT and carry zero amounts (ignore their numeric fields). Lines from documents without types report `item`.
      - `article_id` string, nullable
      - `description` string, required
      - `quantity` number, double, required
      - `unit_type` string, required
      - `unit_price` number, double, required
      - `unit_cost` number, double, nullable
      - `unit_discount_rate` number, double, required
      - `tax_rate` number, double, required
      - `vat_code` string, nullable
      - `vat_description` string, nullable
      - `total_price` number, double, required
      - `total_before_tax` number, double, required
      - `total_tax` number, double, required
      - `total_after_tax` number, double, required
      - `created_at` string, date-time, required
  - `has_more` boolean, required: True if more results exist beyond this page. Use this for the "load more" UI — `data.length` alone is unreliable because a full page may still be the last page.
  - `next_starting_after` string: Opaque cursor for the next page. Present (and non-empty) when `has_more` is `true`; omitted otherwise. Pass the value verbatim as `?starting_after=` on the follow-up request. Clients MUST NOT parse it — today it encodes an offset, tomorrow it may encode a `(created_at, id)` tuple without a wire-visible change.
  - `url` string, required: The request path that produced this list.
  - `date_filter` DateFilter, required: The effective date range the server applied to a date-scoped list request, echoed on the list envelope so clients can render the active filter without re-deriving it. A request that sends no `from`/`to`/`preset` gets the default window, the last 12 months (`rel365`); nothing is carried over between requests. Relative presets are resolved here to concrete dates and roll forward over time.
    - `object` 'date_filter', required
    - `preset` 'rel30' | 'rel90' | 'rel365' | 'year' | 'Q1' | 'Q2' | 'Q3' | 'Q4' | 'month' | 'custom' | 'all', required: Effective selection label. Relative (`rel30`/`rel90`/`rel365`) and absolute (`year`/`Q1`-`Q4`/`month`/`custom`) carry `from`/`to`; `all` omits them.
    - `from` string, date: Inclusive lower bound (YYYY-MM-DD). Omitted when `preset` is `all`.
    - `to` string, date: Inclusive upper bound (YYYY-MM-DD). Omitted when `preset` is `all`.

## Other responses

- `401`: Missing, malformed, expired, or wrong-audience bearer token.
- `402`: The company has no active subscription, or its plan does not include API access. API access is included in the Business and Illimitato plans.
- `403`: The authenticated user lacks the required permission.
- `415`: Content-Type is not `application/json`, or Accept rejects JSON.
- `422`: A request field is missing or invalid (fast-fail).
- `500`: Unhandled server error. Detail is logged, not exposed.

---

[API](https://skmtc.dev/officina/apis/officina-it-api.md) · [All operations](https://skmtc.dev/officina/apis/officina-it-api/llms.txt) · [OpenAPI document](https://skmtc.dev/officina/apis/officina-it-api/revisions/7da3fccfe551?raw)
