---
title: "Update Gl Vat Code"
method: PATCH
path: "/companies/{company_id}/gl/vat-codes/{vat_code_id}"
tags: ["gl-references"]
---

# Update Gl Vat Code

`PATCH /companies/{company_id}/gl/vat-codes/{vat_code_id}`

## 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/companies/{company_id}/gl/vat-codes/{vat_code_id}`
- Auth: none declared

Edit a VAT code's deductible share or its ESTV return box.

Partial update: each field is applied only when its key is present in the body, so an
explicit `null` clears `return_box_code` while an omitted key leaves it alone. An empty
body is a 422, not a silent no-op. Both fields may be sent together; they are applied in
one transaction, so a refusal on either leaves the row untouched.

⚠️ **`return_box_code` is NOT a forward-only edit — it re-declares this code's existing
postings, including in FILED periods.** Only the manual/metadata posting path snapshots
the box onto `gl_vat_posting`; `ar_ap` (every invoice and credit note), the cash book and
expense cards deliberately leave that column NULL even for a code that declares a box,
and the return resolves them with `coalesce(posting.return_box_code,
code.return_box_code)` — i.e. against whatever the code says at the moment the return is
built. A filed period **that carries a `filed_snapshot`** keeps its exported figures — the
PDF, CSV and eMWST XML render from the snapshot, not live — but the per-period drift diff
will start reporting the difference, and the only thing that *names* a re-boxing as the
cause is the **annual** Umsatzabstimmung's `correction_hint`, which annotates and never
suppresses. ⚠️ A period filed **before** snapshots existed has none, so its PDF and CSV
render live and DO move (its XML refuses either way). Use this to place a code that
resolved no box; do not use it to reclassify a code with filed history unless you intend
that restatement.

**Refused (422) when the change moves the code to a different storage convention.** Some
boxes decide not just where the return reports an amount but how `gl_vat_posting` *stores*
it: Ziff **415/420** keep an input-tax correction as a bare positive magnitude (because
`479 = Σ(400,405,410) − Σ(415,420)` subtracts it), Ziff **381** stores a Bezugsteuer
acquisition with the sign of a purchase rather than a sale, and every other box stores the
transaction's own sign. Re-boxing across those lines would split one code's declarations
between two conventions, and a credit note that should reduce a figure would increase it.
A move *within* one convention is allowed — 415 ↔ 420 changes nothing about storage.
Otherwise: create a new code with the box you want and recode onto it whatever this one has
already booked.

⚠️ **A permitted move is not a harmless one.** The refusal guards the stored sign, nothing
else. `return_box_code` is **not** a presentational field: every accepted change still
re-declares this code's existing postings, moving already-declared turnover or input tax
from one ESTV line to another. Treat an allowed re-box as a restatement, not a relabelling.

⚠️ **One door to the mixed state is deliberately still open**, because closing it was
outside the ruling that opened this endpoint: a code can be *created* with
`return_box_code="415"` or `"381"` (`POST …/gl/vat-codes` takes a free, unvalidated,
unstripped string) and then invoiced through `ar_ap`, which stores signed amounts whatever
the box says. Reported for the owner; do not assume the state is unreachable.

`default_deductibility_percent` is the per-code Privatanteil (ZET-234) and decides
`gl_vat_posting.non_deductible_amount`, hence **Ziffer 415 Vorsteuerkorrektur**. Use it
for a mixed business/private expense whose private share is a fixed percentage of the
code. **It changes no already-posted row** — `non_deductible_amount` is snapshotted at
post time, so the new value applies to later postings, and to existing ones only when an
accountant re-runs `prepare` on an **open** VAT period. It may not be sent as `null`.

Under an **Art. 30 three-pot election** the two reductions compose (F2355): the private
share comes first and the sector key applies to the business remainder — 1,000 input tax
at 80 % here and a 75 % residual key deducts 600 and corrects 400 in Ziffer 415. The key
is taken to measure business use only; a key that already nets out private use must not
be combined with a share below 100 % here. Neither order (this PATCH, or electing
three-pot afterwards) is refused any more.

## Path parameters

- `company_id` string, required
- `vat_code_id` string, required

## Headers

- `authorization` string, nullable

## Cookies

- `access_token` string, nullable

## Request body

- GlVatCodeUpdate: Partial update — each field is applied **only when its key is present** in the body (``model_fields_set``), so an explicit ``null`` can clear the box while an omitted key leaves it alone. An empty body is a 422, not a silent no-op. * ``default_deductibility_percent`` — the per-code Privatanteil (ZET-234). **May not be sent as ``null``.** Forward only, with one exception: in a fiscal year with an Art. 30 three-pot election it composes with the sector key (private share first, then the key on the business remainder — F2355), and preparing an OPEN VAT period re-derives that period's input postings on sector-mapped accounts from the code's current share, like the key itself, under the election of each posting's year (a reversal's: its original's). Filed periods, collected-basis carriers and declared tranches, and postings whose year has no election never move. * ``return_box_code`` — the ESTV Ziffer this code declares into. **Never presentational, and never forward-only:** three of the four VAT writers (``ar_ap``, the cash book, expense cards) leave ``gl_vat_posting.return_box_code`` NULL even for a code that declares a box, and the return aggregates ``coalesce(posting.return_box_code, code.return_box_code)`` — so **every** accepted change re-declares this code's existing postings, filed periods included. Some boxes additionally decide how a posting's amount is *stored* (``repos/gl_vat/postings.sign_convention_for_box``): 415/420 keep a magnitude, 381 keeps an acquisition sign, everything else keeps the transaction's own sign. A move between two of those conventions is refused outright. ``direction`` and ``vat_account_code`` remain unpatchable: they are what every posted row was *paired* by, and re-pointing them re-attributes history with no aggregation-time fallback to soften it (ZET-130 blocker 3).
  - `default_deductibility_percent` union: Omit to leave unchanged. Must not be sent as null.
    - number
    - string
  - `return_box_code` string, nullable
  - `deduction_ground` string, nullable: F2482 — the typed ground of a Ziffer 280 deduction: land_value, emission_rights (supplies from 2025 only), margin_purchase or other. Only on a code whose box is 280; null clears it.

## Response `200`

Successful Response

- GlVatCodeOut
  - `id` string, required
  - `company_id` string, required
  - `code` string, nullable
  - `name` string, nullable
  - `direction` string, required
  - `vat_account_code` string, required
  - `company_vat_rate_id` string, nullable
  - `return_box_code` string, nullable
  - `default_deductibility_percent` string
  - `deduction_ground` string, nullable
  - `is_active` boolean, required

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