---
title: "List checkins"
method: GET
path: "/v1/checkins"
tags: ["Checkins"]
---

# List checkins

`GET /v1/checkins`

## Request

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

Returns checkins in the authenticated user's company, newest
first. Filter by status with `?status=active|completed`; search
by customer name with `?q=`; bound by `created_at` with
`?from=` / `?to=` / `?preset=`; paginate with `?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`. Pass `?preset=all`
to list across all time.

The cursor is opaque — clients MUST NOT parse it. Pass back the
value verbatim. `has_more` is `true` when more results exist
beyond this page.

List responses omit `line_items` to keep payloads small. Fetch
the detail endpoint when you need the full shape.

## Query parameters

- `q` string
- `status` 'active' | 'completed'
- `from` string, date
- `to` string, date
- `preset` 'rel30' | 'rel90' | 'rel365' | 'year' | 'Q1' | 'Q2' | 'Q3' | 'Q4' | 'month' | 'custom' | 'all'
- `limit` integer
- `starting_after` string
- `direction` string
- `sort` string

## Response `200`

Page of checkins.

- object
  - `object` 'list', required: Polymorphic discriminator.
  - `data` Checkin[], required: Page of items. Each item carries its own `object` field.
    - `object` 'checkin', required
    - `id` string, required
    - `seq_number` integer, required: Per-company human-readable sequence (e.g. "Checkin #142"). Assigned at create time and stable afterwards.
    - `status` 'active' | 'completed', required: Lifecycle state. Mutated only through `POST /v1/checkins/{id}/transitions`, never via PATCH.
    - `title` string, nullable
    - `comments` string, nullable
    - `internal_comments` string, nullable: Notes visible only to workshop staff.
    - `customer_id` string, required
    - `vehicle_id` string, required
    - `work_category_id` string, nullable
    - `worksheet_id` string, nullable: Set when the checkin has been converted into a worksheet.
    - `quote_id` string, nullable: Set when the checkin has been converted into a quote.
    - `fuel_level` integer, nullable: Free-form integer captured at intake. Convention is 0–100 (percentage) but the API enforces no bounds today.
    - `section1` string, nullable
    - `section2` string, nullable
    - `section3` string, nullable
    - `section4` string, nullable
    - `section5` string, nullable
    - `section6` string, nullable
    - `section7` string, nullable
    - `section8` string, nullable
    - `km` number, nullable: Odometer reading at intake.
    - `created_by` string, required: User id of the staff member who created the checkin.
    - `customer_name` string, required: Denormalized display string of the linked customer. Pre-computed on the entity for list-row rendering without a second request.
    - `vehicle_name` string, required: Denormalized display string of the linked vehicle.
    - `vehicle_license` string, nullable
    - `work_category_name` string, nullable
    - `work_category_ids` string[], required: Every work category ("categoria") of the document, in the order chosen. `work_category_id` (kept for clients that handle a single category) always equals the first. `[]` when the document has none, never null. Available since revision 2026-10-03.
    - `work_categories` WorkCategory[], required: The same list as `work_category_ids` with each category's name, same order. `work_category_name` is the first one's name. Available since revision 2026-10-03.
      - `object` 'work_category', required
      - `id` string, uuid, required
      - `name` string, required
    - `delivered_at` string, date-time, nullable
    - `created_at` string, date-time, required
    - `updated_at` string, date-time, required
    - `deleted_at` string, date-time, nullable: Soft-deletion timestamp. Populated on the response from DELETE /v1/checkins/{id}. Checkins with a non-null deleted_at are not returned by list/detail endpoints — this field appears for the delete response only.
    - `line_items` CheckinLineItem[], nullable: Embedded line items (description-only notes). Populated on detail / batch responses; list GET emits `null` to keep payloads small. Mutate via POST /v1/checkins/{id}/line-items/batch.
      - `object` 'checkin_line_item', required
      - `id` string, required
      - `description` string, 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)
