---
title: "Get Archive Tree"
method: GET
path: "/items/archive/tree"
tags: ["items"]
---

# Get Archive Tree

`GET /items/archive/tree`

## Request

- Base URL: `https://app.zeno-works.ch` (the document declares no server; this is the origin it was published from)
- URL: `https://app.zeno-works.ch/items/archive/tree`
- Auth: none declared

One level of the company's browsable archive (the Documents → Archive page).

The tree is the DB record of what the archiver filed (``Item.archived_path``) —
folders = the distinct next path segments under ``path`` (with counts), files = the
archived items directly in ``path`` (enriched like ``GET /items`` rows; paginated by
``limit``/``offset``). ``path`` is the opaque drill-down token from a previous
response's ``folders[].path`` ('' = root). Scoped to the caller's membership in
``company_id`` (A1).

A folder that exists in more than one storage connection is NOT merged: the response
comes back with ``folder_kind == "storage_connection"``, no files, and one folder per
connection to continue in (ZET-188). That is a normal 200 — the level has a listing,
it is just a choice of drives rather than a choice of sub-folders.

## Query parameters

- `company_id` string, required
- `path` string
- `limit` integer
- `offset` integer

## Headers

- `authorization` string, nullable

## Cookies

- `access_token` string, nullable

## Response `200`

Successful Response

- ArchiveTreeResponse: Archive browser envelope: sub-folders + the files directly in ``path``. ``folder_kind`` says what ``folders`` are: * ``"path"`` — the normal listing: one entry per next path segment under ``path``. * ``"storage_connection"`` — the requested folder exists in MORE THAN ONE storage connection, so the server refuses to merge it (merged paths would name a folder that exists on neither drive). ``files`` is empty, ``total_files`` is 0, and ``folders`` is the choice of drives: one entry per connection holding documents there, whose ``path`` re-enters the SAME folder scoped to that connection. Pick one and continue — this is a 200, not an error; a client that ignores the field still never sees merged data (ZET-188).
  - `folders` ArchiveFolderOut[], required
    - `name` string, required
    - `path` string, required
    - `count` integer, required
  - `files` ItemOut[], required
    - `id` string, required
    - `company_id` string, required
    - `source` 'email' | 'epost' | 'upload' | 'bexio' | 'abacus' | 'filesystem' | 'clouddrive', required
    - `file_id` string, required
    - `sha256` string, required
    - `filename` string, required
    - `size` integer, required
    - `mime_type` string, required
    - `date` string, date-time, required
    - `invoice_date` string, date, nullable
    - `service_period_start` string, date, nullable
    - `service_period_end` string, date, nullable
    - `document_index` integer
    - `page_range` string, nullable
    - `document_count` integer
    - `direction` 'payable' | 'receivable', required
    - `money_source` string, nullable
    - `money_source_override` string, nullable
    - `counterparty_id` string, nullable
    - `archive_status` 'pending' | 'archiving' | 'archived' | 'failed', required
    - `archive_error` string, nullable
    - `archived_at` string, date-time, nullable
    - `storage_connection_id` string, nullable
    - `storage_ref` string, nullable
    - `archived_path` string, nullable
    - `is_archived` boolean, required
    - `triage_status` 'irrelevant' | 'needs_review' | 'unrelated': AI ingest-gate verdict parking an item in the Inbox (pipeline §"Ingest triage", §"Relevance gate"). NULL = not triaged / normal flow. ``irrelevant``/``needs_review`` are the metadata-triage verdicts on a held-unusable item (a human override flips between them; re-analysis resets the columns to NULL). ``unrelated`` is the relevance-gate verdict on a *cleanly extracted* invoice that doculyse's entity resolver matched to neither party of the owning company — the item is held ``pending`` (never archived, no counterparty, never coded) until a human restores it (clears the verdict) or deletes it.
    - `triage_reason` string, nullable
    - `analysis_status` 'pending' | 'analyzing' | 'analyzed' | 'failed', required
    - `analysis_error` string, nullable
    - `is_analyzed` boolean, required
    - `ai_data` unknown
    - `qr_data` unknown
    - `data` unknown
    - `email_id` string, nullable
    - `section` string, nullable
    - `epost_account_id` string, nullable
    - `letter_id` string, nullable
    - `letter_title` string, nullable
    - `letter_type` string, nullable
    - `uploaded_by` string, nullable
    - `bexio_account_id` string, nullable
    - `bexio_invoice_id` string, nullable
    - `bexio_document_nr` string, nullable
    - `bexio_status` string, nullable
    - `bexio_updated_at` string, date-time, nullable
    - `bexio_is_valid_from` string, date-time, nullable
    - `source_payload` unknown
    - `is_duplicate` boolean
    - `duplicate_of` ItemDuplicateOfOut: Why this item carries ``is_duplicate`` (ZET-264). ``null`` when the item is not a duplicate. Projected by the **detail** response and by the **upload** response (ZCT-515 — the surface that first tells a caller ``is_duplicate: true`` must also be able to say of what); list rows keep the boolean badge alone, because naming the siblings there is a query per row. Derived from the same predicate as ``is_duplicate``, so the two can never disagree.
      - `matches` ItemDuplicateMatchOut[], required
        - `item_id` string, required
        - `arms` string[], required
        - `match_key` string, required
      - `truncated` boolean
    - `vat_missing` boolean
    - `counterparty` InvoiageCoreSchemasItemCounterpartyBrief: Nested counterparty summary embedded in an item when requested.
      - `id` string, required
      - `company_id` string, required
      - `kind` string, required
      - `name` string, required
      - `normalized_name` string, required
      - `town` string, nullable
      - `vat_number` string, nullable
    - `is_paid` boolean
    - `due_date` string, nullable
    - `dunning_level` string, nullable
    - `dunning_label` string, nullable
    - `doc_type` string, nullable
    - `document_type` string, nullable
    - `is_credit_note` boolean
    - `card_statement_issuer` string, nullable
    - `counterparty_name` string, nullable
    - `payment` ItemPaymentInfo: Payment-ready instruction for an item, read verbatim from ``qr_data[0]``. Present on an :class:`ItemOut` only when the item is payment-ready (effective ``money_source == "qr"``, exactly one parsed QR, and a complete iban/amount/ currency). Every field comes from the QR (the authoritative payment instruction), NOT the normalized counterparty. ``amount`` is the 2-decimal accounting string.
      - `creditor_name` string, nullable
      - `creditor_iban` string, required
      - `amount` string, required
      - `currency` string, required
      - `reference_type` string, nullable
      - `reference` string, nullable
    - `posting` ItemPostingOut: The ledger projection of one ingested document — the posted/not marker. Present only on the surfaces that project it (the item lists and the item detail read, ZCT-848); everywhere else ``ItemOut.posting`` stays ``None``, which means "not computed here", NOT ``unposted``. Never branch on a missing value. It answers "is it in the journal?", not "may I code it?": a coding row posted without an entry, or an expense-receipt routing row, reads ``unposted`` here while coding the item is still refused as already booked (``gl_autopost.coding_blocker``). ``accounts`` is filled only for :attr:`ItemPostingStatus.posted` and holds **every** operating leg, largest first — a document split across three expense accounts has no single answer, and silently showing the first line would be a lie. It may legitimately be empty (an entry with only control/VAT legs).
      - `status` 'posted' | 'reversed' | 'held' | 'unposted', required: Where an ingested document stands in the general ledger (ZET-98/103/108). Deliberately NOT a boolean: a boolean collapses four states a treuhänder has to tell apart, and "not posted" alone cannot say *why*. - ``posted`` — a coding decision for this document points at a journal entry whose ``status`` is ``posted``. This is the only value that means "it is in the ledger"; :attr:`ItemPostingOut.accounts` says where. - ``reversed`` — the document was booked and that entry was reversed. The ledger no longer carries it, so it is **not** posted (ZET-95), but it is a materially different state from "never touched": it needs re-booking. - ``held`` — the AI accountant produced a coding proposal that did not clear the autonomy policy and is waiting for a human. Nothing is in the ledger. - ``unposted`` — everything else: no coding decision at all, a shadow-mode decision (``assist``: it *would* have posted but did not), or a decision of a kind that books nothing.
      - `journal_entry_id` string, nullable
      - `accounts` ItemPostingAccountOut[]
        - `account_id` string, required
        - `code` string, required
        - `name` string, required
        - `amount` string, required
      - `coding_pending` boolean
      - `filed_with` ItemFiledWithOut: The booking a re-ingested COPY of an invoice was filed with (ZEN-1, ZCT-945). The coder's dunning linkage (``ap_dunning.try_link_ap_document``) recognises a second upload of an invoice that is already booked and files it against that booking's open item instead of booking it twice. It writes no decision, so the copy's own projection is ``unposted`` and the lists used to read "Not posted" — to the reader the AI looked as if it had stopped posting. This names the booking the copy belongs to. Set only where "already booked" is TRUE (:func:`services.item_posting.posting_map`): an advisory, non-reminder, non-collision link whose holder entry is posted, and — for the weaker payment-reference tier — only for a copy dated like the booked invoice. ``gross`` / ``currency`` are the BOOKED document's; ``amount_differs`` says the copy prints another total or currency, so the reader checks the booking rather than trusting the badge (the linker matches amounts within a band, not exactly).
        - `journal_entry_id` string, required
        - `entry_no` string, nullable
        - `entry_date` string, date, required
        - `match_tier` string, required
        - `gross` string, required
        - `currency` string, required
        - `amount_differs` boolean
    - `analysis_fault` IngestFaultOut: Why an ingest record failed or is parked, and what removes the cause.
      - `code` 'transient' | 'quota_held' | 'defect_fixed' | 'platform_defect' | 'bytes_gone' | 'too_large' | 'unreadable' | 'unexplained' | 'unsupported_type' | 'parse_error' | 'format_unknown' | 'not_a_statement' | 'no_account_id' | 'nothing_readable' | 'no_statement_found' | 'fiscal_year_undeterminable' | 'corrupt_archive' | 'empty_archive' | 'ambiguous_tabular' | 'analysis_failed' | 'statement_format_not_importable' | 'statement_beside_invoice' | 'statement_beside_card_bill' | 'accounting_document_not_importable' | 'statement_import_failed' | 'archive_incomplete' | 'encrypted' | 'corrupt' | 'limit_exceeded' | 'ratio' | 'depth_exceeded' | 'empty' | 'archive_no_connection' | 'archive_connection_disabled' | 'archive_reconnect_required' | 'archive_no_template' | 'archive_upload_failed' | 'triage_unrelated' | 'triage_needs_review' | 'triage_irrelevant', required: The closed vocabulary. The SPA has exactly one row per member (a test enforces it).
      - `retry` 'auto' | 'user' | 'none', required: Whether running the same operation again can change the outcome.
      - `actions` IngestFaultAction[], required
      - `params` object
    - `archive_fault` IngestFaultOut: Why an ingest record failed or is parked, and what removes the cause.
      - `code` 'transient' | 'quota_held' | 'defect_fixed' | 'platform_defect' | 'bytes_gone' | 'too_large' | 'unreadable' | 'unexplained' | 'unsupported_type' | 'parse_error' | 'format_unknown' | 'not_a_statement' | 'no_account_id' | 'nothing_readable' | 'no_statement_found' | 'fiscal_year_undeterminable' | 'corrupt_archive' | 'empty_archive' | 'ambiguous_tabular' | 'analysis_failed' | 'statement_format_not_importable' | 'statement_beside_invoice' | 'statement_beside_card_bill' | 'accounting_document_not_importable' | 'statement_import_failed' | 'archive_incomplete' | 'encrypted' | 'corrupt' | 'limit_exceeded' | 'ratio' | 'depth_exceeded' | 'empty' | 'archive_no_connection' | 'archive_connection_disabled' | 'archive_reconnect_required' | 'archive_no_template' | 'archive_upload_failed' | 'triage_unrelated' | 'triage_needs_review' | 'triage_irrelevant', required: The closed vocabulary. The SPA has exactly one row per member (a test enforces it).
      - `retry` 'auto' | 'user' | 'none', required: Whether running the same operation again can change the outcome.
      - `actions` IngestFaultAction[], required
      - `params` object
    - `triage_fault` IngestFaultOut: Why an ingest record failed or is parked, and what removes the cause.
      - `code` 'transient' | 'quota_held' | 'defect_fixed' | 'platform_defect' | 'bytes_gone' | 'too_large' | 'unreadable' | 'unexplained' | 'unsupported_type' | 'parse_error' | 'format_unknown' | 'not_a_statement' | 'no_account_id' | 'nothing_readable' | 'no_statement_found' | 'fiscal_year_undeterminable' | 'corrupt_archive' | 'empty_archive' | 'ambiguous_tabular' | 'analysis_failed' | 'statement_format_not_importable' | 'statement_beside_invoice' | 'statement_beside_card_bill' | 'accounting_document_not_importable' | 'statement_import_failed' | 'archive_incomplete' | 'encrypted' | 'corrupt' | 'limit_exceeded' | 'ratio' | 'depth_exceeded' | 'empty' | 'archive_no_connection' | 'archive_connection_disabled' | 'archive_reconnect_required' | 'archive_no_template' | 'archive_upload_failed' | 'triage_unrelated' | 'triage_needs_review' | 'triage_irrelevant', required: The closed vocabulary. The SPA has exactly one row per member (a test enforces it).
      - `retry` 'auto' | 'user' | 'none', required: Whether running the same operation again can change the outcome.
      - `actions` IngestFaultAction[], required
      - `params` object
  - `total_files` integer, required
  - `folder_kind` 'path' | 'storage_connection'

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/zeno-works/apis/zeno-api.md) · [All operations](https://skmtc.dev/zeno-works/apis/zeno-api/llms.txt) · [OpenAPI document](https://skmtc.dev/zeno-works/apis/zeno-api/revisions/1eb93dde146c?raw)
