{
  "openapi": "3.0.4",
  "info": {
    "title": "Fluit Public API",
    "description": "REST API for integrating external systems with Fluit ERP: webshops, WMS, EDI,\nBI tools and custom integrations. The API is scoped to a single tenant (your company) —\nthe credential you call with determines which company's data you read and write.\n\n# Authentication\n\nTwo credentials reach this API. They grant the same operations; what differs is who the\ncalls are attributed to.\n\n**API key** — for machine-to-machine integrations. A key belongs to the company, not to a\nperson, so its calls are anonymous within the company.\n\n**OAuth 2.1** — for integrations whose calls should be traceable to a person. A user\napproves the connection, and every read and write the token makes is recorded against\nthat user and your client's name in the company's activity log.\n\nPick per integration. A nightly EDI job wants a key; an app people sign into wants OAuth.\n\nThe two do **not** reach the same operations. An API key has no user behind it, so only\nits scopes bound it. An OAuth connection acts on the approving user's mandate and is\nbounded by their permissions in Fluit as well — a connection approved by someone who\ncannot post inventory counts cannot post them either, and the call returns `403` with\n`Permission.Denied`. If your integration needs the full surface, have it approved by a\nuser whose role covers it, or use an API key.\n\n# Getting started with an API key\n\n1. Create an API key in Fluit under **Settings → API keys**. The key is shown once —\n   store it securely. Keys are prefixed `fluit_live_sk_` (production) or `fluit_test_sk_` (test).\n2. Call the API with the key in the `X-Api-Key` header:\n\n```bash\ncurl https://api.fluit.cloud/preview/items?pageSize=5 \\\n  -H \"X-Api-Key: fluit_live_sk_...\"\n```\n\n# Getting started with OAuth 2.1\n\nThe authorization server is built in, and everything about it is discoverable — no\ncredentials to exchange with us up front.\n\n1. Fetch `/.well-known/oauth-protected-resource/preview` for the resource identifier and\n   its supported scopes, and `/.well-known/oauth-authorization-server` for the endpoints.\n2. Register your client at `POST /oauth/register` (RFC 7591 dynamic client registration).\n   No client secret is issued or accepted — PKCE (S256) is what protects the exchange, and\n   it is mandatory.\n3. Send the user to `/oauth/authorize` with `resource=https://api.fluit.cloud/preview`\n   and the scopes you need. They sign in, pick the company, and approve. Passing the\n   `resource` parameter matters: it is what binds the grant to this API rather than to\n   another of our protected surfaces.\n4. Exchange the code at `POST /oauth/token`, then call the API with the access token:\n\n```bash\ncurl https://api.fluit.cloud/preview/items?pageSize=5 \\\n  -H \"Authorization: Bearer <access token>\"\n```\n\nRefresh tokens rotate on every use: you get a new one with each refresh, and the spent one\nstops working. Keep only the newest, and treat `invalid_grant` on refresh as \"start the\nflow again\" rather than as something to retry.\n\nThe token is confined to this API. It cannot be used against any other Fluit surface, and\na token issued for another surface cannot be used here.\n\nA user can see and disconnect their connections under **My settings → Connections**; an\nadministrator sees the company's under **Settings → Connections**. Assume a connection can\nbe revoked at any time and handle `401` by starting the flow again.\n\n## Scopes\n\nEvery credential carries a space-separated list of scopes, and every operation requires\none. The scope is `{resource}:read` for reads and `{resource}:write` for writes, where the\nresource is the operation's tag in lower kebab-case — `items:read`, `sales-orders:write`,\n`inventory:write`. Each operation states its scope in the description and in the\n`x-required-scope` extension.\n\nOAuth connections use two surface-wide scopes instead: `preview:read` covers every read,\nand `preview:write` covers everything. The list above is the right granularity for a key\nan administrator configures once; it is the wrong thing to put in front of a person\napproving a connection, so consent asks about reading and acting, and the user can approve\na read-only connection by declining the write half.\n\nGive a key only what its integration needs. A webshop that reads the catalogue and places\norders wants `items:read sales-orders:write`, and nothing more — with that list it cannot\nwrite off stock or post an inventory count, even though those endpoints exist on the same\nAPI. Use `*` for a key that should reach everything.\n\nCalling an operation the credential lacks the scope for returns `403` with the required\nand granted scopes in the problem details.\n\n> Keys created before scopes were enforced have an empty scope list. Those keep working\n> with unrestricted access, which is the access they already had. Set scopes on the key to\n> narrow it — there is no way to widen an empty list, because it is already unlimited.\n\n# Your first order\n\nNote the required `Idempotency-Key` on POST:\n\n```bash\ncurl -X POST https://api.fluit.cloud/preview/orders \\\n  -H \"X-Api-Key: fluit_live_sk_...\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"customerNumber\": \"CUST-001\", \"lines\": [ { \"itemNumber\": \"WIDGET-A\", \"quantity\": \"10\" } ] }'\n```\n\n# Conventions\n\n- **Business keys, not GUIDs.** Resources are addressed by their business keys, and `*Code`\n  is used for reference data (warehouses, payment terms, …). List the valid codes via the\n  Reference endpoints.\n\n  | Resource | Key in the URL |\n  | --- | --- |\n  | Customers | `customerNumber` |\n  | Items | `itemNumber` |\n  | Sales orders | `orderNumber`, lines by `lineNumber` |\n  | Suppliers | `supplierNumber` |\n  | Purchase orders | `orderNumber`, lines by `lineNumber` |\n  | Tickets | `ticketNumber` |\n\n  Sales orders and purchase orders live under different paths (`/orders` and\n  `/purchase-orders`), so an order number is only ever ambiguous across the two if you\n  reuse the same number series for both.\n- **Decimals are strings.** All monetary amounts and quantities are serialised as decimal\n  strings (`\"123.45\"`, invariant format) to avoid IEEE 754 floating-point errors.\n  Requests accept both strings and numbers; responses always return strings.\n  Invariant means `.` as the decimal separator and no thousands separator — `\"1234.50\"`.\n  A value in any other format (`\"1 234,50\"`, `\"1,234.50\"`) is rejected with `400`, never\n  guessed at: `\"1,5\"` could as easily mean 15 as 1.5, and a quantity is not something to\n  get approximately right. Format for the wire, not for a reader — `toFixed(2)` in\n  JavaScript, `str(Decimal(...))` in Python, `ToString(CultureInfo.InvariantCulture)` in\n  .NET. The same rule applies to decimal query parameters such as `?quantity=`.\n  Check the item's `decimalPlaces` for how many decimals a quantity may have.\n- **Dates and times.** Dates are ISO 8601 (`2026-06-11`). Timestamps are UTC and carry the\n  `Z` designator (`2026-06-09T22:07:47.7639194Z`), so `new Date(...)` in JavaScript and\n  `datetime.fromisoformat(...)` in Python both resolve them to the right instant without\n  any correction on your side. Request parameters are equally forgiving: `modifiedSince`\n  accepts `Z`, a numeric offset or no designator and resolves all three to the same\n  instant.\n- **Fields are nullable unless the schema says otherwise.** This bites on fields that look\n  mandatory: `baseUnitCode` is null for items with no unit configured, `salesPrice` is null\n  for items with no list price, and `modifiedDate` is null for records that have never been\n  changed since creation. When syncing on `modifiedDate`, fall back to `createdDate`.\n- **Enums are strings.** Status fields and similar are serialised as enum names\n  (`Placed`, `Released`, `Closed`, …) and documented per field. Enum values in query-string\n  filters are matched case-insensitively; an unknown value returns `400` rather than an\n  empty result.\n  Treat enum values as open — new ones may be added without a version bump.\n- **Resources link to themselves.** Every resource that has its own URL carries `links.self`,\n  the canonical URL of that resource. `POST` responses return the same representation as the\n  corresponding `GET`, with the URL in the `Location` header as well. Rows that are only ever\n  read through their parent — order lines, contacts, addresses, packages, reference data —\n  have no self link, because they have no address of their own.\n- **PATCH is JSON Merge Patch.** Only fields present in the body are updated.\n  Pass `null` to clear a nullable field; omitted fields are left unchanged.\n  A field that is not part of the endpoint's contract is rejected with `400`, naming the\n  field and listing the ones it accepts — so a misspelling fails loudly instead of looking\n  like a change that did not take. The two line endpoints\n  (`PATCH /preview/orders/{orderNumber}/lines/{lineNumber}` and its purchase-order\n  counterpart) ignore unknown fields instead; their descriptions say so.\n- **Country codes** are ISO 3166-1 alpha-2 (`SE`), **currency codes** ISO 4217 (`SEK`).\n\n# Prices and stock\n\nTwo fields on the item representation are routinely mistaken for something they are not.\nBoth mistakes are silent — you get a plausible number, not an error.\n\n- **`salesPrice` is the item's list price, not the price anyone pays.** It ignores price\n  lists, customer agreements, campaigns and volume breaks. Call\n  `GET /preview/items/{itemNumber}/price` to get the price an order line would actually\n  receive, with `?customerNumber=` for customer-specific pricing and `?quantity=` for\n  volume tiers. The two commonly differ by double-digit percentages. Use `salesPrice`\n  only where you genuinely want an uncontracted reference price.\n- **The item list carries no stock.** `GET /preview/items` returns no quantity at all.\n  Availability has its own endpoints: `GET /preview/inventory/availability` covers many\n  items in one call — pass up to 200 item numbers in `?itemNumbers=`, or page through the\n  whole stocked catalogue — and `GET /preview/items/{itemNumber}/availability` covers one.\n  Use the bulk endpoint for a catalogue sync, with `?modifiedSince=` so a recurring poll\n  only pays for what moved; one call per item costs 1 + N against the per-minute quota.\n  Remember that `availableQuantity` (on hand minus reservations) is the number you can\n  promise — not `quantityOnHand`.\n\n# Calling from a browser\n\nThe API sends `Access-Control-Allow-Origin: *` and allows `x-api-key` in the preflight,\nso a browser page can call `/preview` directly with no proxy. That is deliberate, and it\nsuits internal tools and prototypes.\n\nIt does not make the key safe in client code. Anything in a page's JavaScript is readable\nby every visitor, and a leaked key grants full access to the tenant's data. For anything\nuser-facing, keep the key on a server you control and let the browser talk to that server\ninstead — or have each user supply their own key at runtime.\n\n# Flows\n\n## Purchasing: order and receive goods\n\n1. `POST /preview/purchase-orders` with `supplierNumber` and lines. The order is created in\n   `Draft` and nothing is sent to the supplier yet. Omit `unitPrice` to use the supplier\n   price list, and `unit` to use the item's base unit.\n2. `POST /preview/purchase-orders/{orderNumber}/send` moves it to `Sent`. By default this\n   only records that the order went out — pass `{\"sendEmail\": true}` if you want Fluit to\n   email the PDF to the supplier rather than sending it yourself over EDI.\n3. `POST /preview/purchase-orders/{orderNumber}/confirm` when the supplier confirms. If they\n   came back with different quantities or dates, `PATCH` the affected lines first.\n4. `POST /preview/purchase-orders/{orderNumber}/lines/{lineNumber}/receive` as goods arrive.\n   Each call books stock, creates an inventory transaction and advances the line and order\n   to `PartiallyReceived` and then `Received`. Call it once per delivery for partial\n   deliveries.\n5. `POST /preview/purchase-orders/{orderNumber}/close` if the supplier will not deliver the\n   remainder — that settles the order without waiting for the outstanding quantity.\n\nReceiving is not reversible through this API, so retries matter: a repeated call with the\nsame `Idempotency-Key` replays the original response instead of booking the goods twice.\n\n## Support: take in a ticket from your own form\n\n1. `POST /preview/tickets` with `title`, `description` and — if you have it — the\n   reporter's `contactEmail` and `customerNumber`. That is the whole contract; the\n   endpoint is meant to sit behind a contact form on your own site.\n2. The reporter gets a confirmation mail with the ticket number, and your agents see the\n   ticket in the same queue as tickets phoned in or mailed to the support mailbox.\n3. `GET /preview/tickets/{ticketNumber}` reads back the current status, so a \"track my\n   ticket\" page can show the reporter where their case stands.\n\nAnswers are written by your agents in Fluit and reach the reporter by email; replies to\nthat mail land back on the same ticket. This API is the way in, not a chat channel.\n\n## Configurator: sell a made-to-measure product\n\nSome items are not picked off a shelf — they are built to the customer's measurements and\nchoices. Curtains, blinds and awnings are the archetype: width and height drive the fabric\nconsumption, the fabric and the control type drive the price, and no two orders are alike.\nThese items are ordered through `/preview/configurations` rather than as a plain order line,\nso the choices survive into production.\n\n1. `GET /preview/items?isConfigurable=true` finds the items that have a configurator.\n2. `GET /preview/items/{itemNumber}/configuration` returns the whole form definition in one\n   call: the features, their input types and bounds, and the selectable options. Each\n   feature's `featureType` tells you which field to send back — `Number` → `number`,\n   `Selection` → `optionCode`, `Boolean` → `boolean`, `ItemSelection` → `itemNumber`,\n   `Text` → `text`. `Calculated` features take no input.\n3. `POST /preview/configurations/calculate` on every change while the customer configures.\n   It returns the price for the current choices plus `resolvedValues` — the derived numbers\n   such as area and fabric consumption, so you do not have to reimplement the formulas. An\n   incomplete configuration is a normal state, not an error: it comes back as `200` with\n   `isValid: false` and every problem listed in `validationErrors`, ready to show at the\n   right field. This is the one POST that does not require an `Idempotency-Key`.\n4. `POST /preview/configurations` once the customer is happy. The response carries a\n   `configurationNumber` — the business key for everything that follows — and the price.\n   `customerNumber` may be left out here and attached later, which is what a storefront that\n   configures before asking who the customer is needs.\n5. `POST /preview/configurations/{configurationNumber}/reconfigure` to change it later.\n   Every field is optional: omit `values` to keep the choices and change only the quantity,\n   pass `customerNumber` to claim an anonymous configuration. When `values` *is* present it\n   replaces the whole set. The response is the updated, repriced configuration.\n6. `POST /preview/configurations/{configurationNumber}/order` turns it into a sales order and\n   returns the order. Add freight or more lines through the order endpoints, then\n   `POST /preview/orders/{orderNumber}/place`. Behind the line, the configuration becomes a\n   work order carrying the exploded bill of materials and routing, so production knows what\n   to build.\n\nA configurator produces abandoned sessions: `DELETE /preview/configurations/{configurationNumber}`\ndiscards one that was never ordered. A configuration that has become an order is frozen —\nreconfiguring or deleting it returns `409`, and it disappears from\n`GET /preview/configurations` without leaving a tombstone, so store the `orderNumber` from\nthe /order response if you keep local copies.\n\n### Pricing a configuration\n\nThe price is the item's own price from the price hierarchy (customer price lists,\nagreements, campaigns, volume breaks) plus the configuration surcharge. Three things are\nworth knowing before you build against it:\n\n- **It is a live price, not a locked quote.** Both `calculate` and the order conversion run\n  the price engine at the moment they are called, so a campaign that starts or expires in\n  between moves the price. The order always uses the customer's currency; a `currencyCode`\n  passed to `calculate` affects that calculation only.\n- **Automatic customer discounts do not apply.** The composed price is set as a manual unit\n  price on the line, which bypasses the discount engine. Price lists, agreements, campaigns\n  and volume breaks are already reflected in the base price.\n- **A choice that links an item does not change the price by itself.** When an option has a\n  `linkedItemNumber`, that item is added to the bill of materials as a cost line and the\n  option's `priceImpact` is deliberately ignored. To make a choice cost more, give it a\n  `priceImpact` without a linked item, or drive the price from a `Calculated` feature.\n\n# Pagination and syncing\n\nList endpoints are paginated with `?page=` (1-based) and `?pageSize=` (default 50, max 200)\nand respond with:\n\n```json\n{ \"items\": [], \"totalCount\": 0, \"page\": 1, \"pageSize\": 50,\n  \"totalPages\": 0, \"hasPreviousPage\": false, \"hasNextPage\": false }\n```\n\n# Incremental sync\n\nA sync needs three things: what was created, what changed, and what was removed. Creates and\nchanges come from the list endpoints; removals need a separate feed, because a deleted record\nleaves nothing behind for a list endpoint to return.\n\n**Upserts — `?modifiedSince=` (UTC ISO 8601).** Store the timestamp at which you started the\nprevious sync and pass it on the next run. Both created and modified records are returned.\nA change anywhere inside the record counts: editing an order line moves the order's\n`modifiedDate`, so nothing can change below the level of the resource you are polling\nwithout the resource itself showing up in the delta.\n\n**Removals — `GET /preview/deletions?deletedSince=`.** Deletions cannot be observed from a\nlist endpoint. A deleted customer, supplier, purchase order or configuration is really gone,\nso it simply stops appearing — which is indistinguishable from \"unchanged since your last\npoll\". Every deletion is instead recorded in a log, written in the same transaction as the\ndeletion itself, and read from this endpoint. Each entry carries the `resource`, the `id` and\nthe `businessKey` the record had when it was deleted, so you can match it against your copy.\n\nA sync run therefore looks like:\n\n```\nsince = <timestamp stored at the start of the previous run>\nnow   = <timestamp now, stored for the next run>\n\nGET /preview/customers?modifiedSince={since}        # and the other collections you mirror\nGET /preview/deletions?deletedSince={since}         # what to retire\n```\n\nBoth directions are safe to re-read from a slightly earlier timestamp: applying the same\nupsert or the same deletion twice has no further effect. Prefer overlapping a little over\ncutting it fine.\n\n**Conditional reads — `ETag` / `If-None-Match`.** `GET` on a single record returns a weak\n`ETag`. Pass it back in `If-None-Match` and you get `304 Not Modified` with an empty body\nwhile the record is unchanged. The validator follows the whole record, nested parts included,\nso a `304` is a real promise that nothing in the representation has moved.\n\n# Idempotency\n\nAll POST requests require an `Idempotency-Key` header — a unique value (UUID recommended,\nmax 255 characters) per logical attempt. There are two exceptions:\n`POST /preview/configurations/calculate`, which has no side effects and is a POST only\nbecause its input does not fit in a URL, and the `multipart/form-data` file uploads\n(`POST /preview/tickets/{ticketNumber}/attachments` and\n`POST /preview/channels/{channelCode}/media`), whose bodies cannot be buffered and hashed\nthe way a JSON request can — retrying one of those may create a second copy, so check\nbefore you retry.\n\n- **Retrying with the same key and body** returns the original response unchanged\n  (marked with the `Idempotency-Replayed: true` header) instead of e.g. creating\n  a duplicate order after a network timeout.\n- **Reusing a key** for a different endpoint or body returns `422 Unprocessable Entity`\n  with `code: \"idempotencyKey.conflict\"`.\n- **Concurrent requests** with the same key are serialised; if the first is still running\n  after 30 s the second receives `503` with a `Retry-After` header.\n- Stored responses expire after **24 hours**.\n\nKeys are scoped to the credential that used them — your API key, or your OAuth connection.\nTwo integrations against the same company never collide, so you are free to generate keys\nhowever you like without coordinating with anyone else.\n\nGenerate a new key for every new logical request; reuse the key only when retrying\nthe same request.\n\n# Errors\n\nErrors follow RFC 7807 (`application/problem+json`):\n\n```json\n{\n  \"type\": \"https://tools.ietf.org/html/rfc7231#section-6.5.1\",\n  \"title\": \"customerNumber\",\n  \"detail\": \"Customer 'CUST-999' not found.\",\n  \"status\": 400\n}\n```\n\n| Status | Meaning |\n| ------ | ------- |\n| 400 | Validation error — an unknown business key, an invalid request body field, or an unknown enum value in a query filter |\n| 401 | Missing, invalid or expired credential — no API key, or a bearer token that no longer authenticates |\n| 403 | The credential is valid but not permitted to perform the operation |\n| 404 | The resource in the URL does not exist |\n| 409 | The operation conflicts with the resource's state (e.g. cancelling a shipped order) |\n| 413 | `POST` body larger than 1 MB, when the request declares a `Content-Length` |\n| 422 | Idempotency-Key reused for a different request |\n| 429 | Rate limit exceeded — back off per the `Retry-After` header |\n| 500 | Unexpected server error. Safe to retry with the same `Idempotency-Key` — server errors are never replayed from cache |\n\nField-level problems are listed in the `errors` extension array, one entry per violation with a\n`code` (the field or business rule) and a `description`. Request body constraints published in\nthis document — required fields, maximum lengths, patterns and ranges — are enforced; a violation\nreturns `400` with the offending field in `errors`. Nested fields use a dotted path,\ne.g. `lines[0].discountPercent`.\n\nTwo cases fall outside this shape and return a plain `400` without a problem+json body:\na request body that is not well-formed JSON, and a query parameter other than an enum filter\n(`page`, `pageSize`, `quantity`, dates and `modifiedSince`) that cannot be parsed into its\ndeclared type. Enum filters such as `?status=` are parsed by the API itself and do produce\nthe `errors` array.\n\n# Rate limiting\n\nRequests are limited to **1000 per minute per credential** (fixed window) — per API key,\nor per access token for an OAuth connection. `429` responses carry `Retry-After` in\nseconds — honour it rather than retrying on a fixed delay.\n\nWhere the quota headers `X-RateLimit-Limit`, `X-RateLimit-Remaining` and\n`X-RateLimit-Reset` are present they describe the current window, but they are not\nemitted on every deployment. Treat them as advisory: read them when they are there,\nand never make your backoff conditional on finding them. Code that only slows down once\n`X-RateLimit-Remaining` gets low will otherwise run flat out into a `429`.\n\n# Preview status\n\nThe API is mounted under `/preview` and is in preview: the schema can change without\nnotice until the stable `/v1` release. Breaking changes are listed in the changelog.\nQuestions or access requests: [info@fluit.se](mailto:info@fluit.se).",
    "contact": {
      "name": "Fluit",
      "url": "https://fluit.se",
      "email": "info@fluit.se"
    },
    "version": "preview"
  },
  "servers": [
    {
      "url": "https://api.fluit.cloud",
      "description": "Production"
    }
  ],
  "paths": {
    "/preview/brands": {
      "post": {
        "tags": [
          "Brands"
        ],
        "summary": "Create a brand",
        "description": "Creates a brand that items can carry. `code` is the business key: it is what `brandCode` on an item row references, so it should be stable.\n\nKnown error codes: `Brand.CodeNotUnique`.\n\nRequires the `brands:write` scope.",
        "operationId": "Preview_CreateBrand",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBrandRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Code and name",
                  "value": {
                    "code": "KORDZ",
                    "name": "Kordz"
                  }
                },
                "full": {
                  "summary": "With logo and site",
                  "value": {
                    "code": "KORDZ",
                    "name": "Kordz",
                    "description": "Australian maker of HDMI and installation cabling.",
                    "logoUrl": "https://cdn.example.com/brands/kordz.png",
                    "websiteUrl": "https://kordz.com",
                    "sortOrder": 10
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicBrandResponse"
                }
              }
            }
          },
          "400": {
            "description": "The code is already taken.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'brands:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "brands:write"
      },
      "get": {
        "tags": [
          "Brands"
        ],
        "summary": "List brands",
        "description": "Returns brands ordered by code. `search` matches code and name, case-insensitively and on any part of the value.\n\nThe response is a paged envelope: `{ items, totalCount, page, pageSize, totalPages, hasPreviousPage, hasNextPage }`. `pageSize` defaults to 50 and is capped at 200.\n\nRequires the `brands:read` scope.",
        "operationId": "Preview_ListBrands",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Case-insensitive partial match on code and name.",
            "schema": {
              "type": "string",
              "description": "Case-insensitive partial match on code and name."
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicBrandResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'brands:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "brands:read"
      }
    },
    "/preview/brands/{code}": {
      "get": {
        "tags": [
          "Brands"
        ],
        "summary": "Get a brand",
        "description": "Returns one brand by its code, in the same shape as POST /preview/brands.\n\nRequires the `brands:read` scope.",
        "operationId": "Preview_GetBrand",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "description": "Code of the brand.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the brand."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicBrandResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No brand with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'brands:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "brands:read"
      }
    },
    "/preview/categories": {
      "post": {
        "tags": [
          "Categories"
        ],
        "summary": "Create an item category",
        "description": "Creates a category that items can be filed under. `code` is the business key: it is what `categoryCode` on an item row references, so it should be stable.\n\n`parentCode` nests the category under an existing one. Load a tree parents-first — a parent that does not exist yet is rejected with 400 naming the field, not created implicitly.\n\nKnown error codes: `ItemCategory.CodeNotUnique`, `categoryCode` (unknown parent).\n\nRequires the `categories:write` scope.",
        "operationId": "Preview_CreateCategory",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCategoryRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Root category",
                  "value": {
                    "code": "SPEAKERS",
                    "name": "Speakers"
                  }
                },
                "full": {
                  "summary": "Nested category",
                  "value": {
                    "code": "FLOORSTANDING",
                    "name": "Floorstanding speakers",
                    "description": "Full-range speakers that stand on the floor.",
                    "parentCode": "SPEAKERS",
                    "slug": "floorstanding-speakers",
                    "sortOrder": 10
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCategoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "The code is already taken, or parentCode does not exist.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'categories:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "categories:write"
      },
      "get": {
        "tags": [
          "Categories"
        ],
        "summary": "List item categories",
        "description": "Returns categories ordered by code. `search` matches code and name, case-insensitively and on any part of the value.\n\nThe response is a paged envelope: `{ items, totalCount, page, pageSize, totalPages, hasPreviousPage, hasNextPage }`. `pageSize` defaults to 50 and is capped at 200.\n\n`parentCode` on each row is how the tree is read back — a root category has null.\n\nRequires the `categories:read` scope.",
        "operationId": "Preview_ListCategories",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Case-insensitive partial match on code and name.",
            "schema": {
              "type": "string",
              "description": "Case-insensitive partial match on code and name."
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicCategoryResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'categories:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "categories:read"
      }
    },
    "/preview/categories/{code}": {
      "get": {
        "tags": [
          "Categories"
        ],
        "summary": "Get an item category",
        "description": "Returns one category by its code, in the same shape as POST /preview/categories.\n\nRequires the `categories:read` scope.",
        "operationId": "Preview_GetCategory",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "description": "Code of the category.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the category."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCategoryResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No category with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'categories:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "categories:read"
      },
      "patch": {
        "tags": [
          "Categories"
        ],
        "summary": "Update an item category",
        "description": "Partially updates a category's name, description, slug, sort order and search-result texts. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. code cannot be changed, because it is the resource's address and what item rows reference. name cannot be set to null.\n\nslug is normalized the same way as in the admin (lowercase, diacritics folded, spaces to hyphens). Changing it moves the category page to a new URL and automatically creates a 301 from the old address on every active channel, so incoming links and their ranking survive. Passing null makes the category fall back to its code as URL segment, with the same 301.\n\nmetaTitle and metaDescription are what the category page shows in search results, translated per language like the name. Search engines cut titles around 60 characters and descriptions around 155; longer text is accepted (up to 200 and 500) but may be cut. Pass null to fall back to the name and description.\n\nRead the result back with GET /preview/categories/{code}.\n\nRequires the `categories:write` scope.",
        "operationId": "Preview_PatchCategory",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "description": "Code of the category to update.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the category to update."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchCategoryRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchCategoryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a field present in it failed validation, name was sent as null, or slug contains no letter or digit.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No category with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "ItemCategories.SlugNotUnique — another category already uses that slug.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'categories:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "categories:write"
      }
    },
    "/preview/items/{itemNumber}/channels": {
      "post": {
        "tags": [
          "Channels"
        ],
        "summary": "Publish an item on a channel",
        "description": "Publishing is opt-in: an item is only visible in a channel once this record exists. Every content field is an override — omit it and the channel uses the item's own value. An item can only be published once per channel; publishing it again returns 409. Omitting the slug generates a unique one from the item's name; supplying one that another item in the channel already uses returns 409. The response body is the same representation as GET /preview/items/{itemNumber}/channels/{channelCode}; the canonical URL is returned in the Location header and in links.self.\n\nRequires the `channels:write` scope.",
        "operationId": "Preview_CreateItemChannel",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to publish.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to publish."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateItemChannelRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal — publish with the item's own content",
                  "value": {
                    "channelCode": "webshop-se"
                  }
                },
                "full": {
                  "summary": "Full — channel-specific content, SEO and scheduling",
                  "value": {
                    "channelCode": "webshop-se",
                    "isActive": true,
                    "name": "Widget Pro 3000 – proffsmodell",
                    "shortDescription": "Vår mest sålda widget.",
                    "metaTitle": "Widget Pro 3000 | Köp online",
                    "metaDescription": "Proffswidget med 5 års garanti. Fri frakt över 500 kr.",
                    "slug": "widget-pro-3000",
                    "showStock": true,
                    "stockDisplayMode": "InStockOutOfStock",
                    "sortOrder": 10,
                    "isFeatured": true,
                    "publishDate": "2026-09-15T00:00:00+02:00"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemChannelResponse"
                }
              }
            }
          },
          "400": {
            "description": "No channel with that code, or a field failed validation.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "ItemChannel.AlreadyExists — the item is already published on that channel; patch the existing publication instead. ItemChannel.SlugNotUnique — another item in the channel already uses that slug.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'channels:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "channels:write"
      },
      "get": {
        "tags": [
          "Channels"
        ],
        "summary": "List the channels an item is published on",
        "description": "Publishing is opt-in: an item is only visible in a channel once a publication exists, so an empty list means the item is not for sale anywhere. Sorted by sort order, then item number and channel code. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200. Every content field is null when the channel uses the item's own value, so \"not set\" stays distinguishable from \"set to the same text\". Delta sync: ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Newly created publications are included even though they have no modifiedDate yet.\n\nRequires the `channels:read` scope.",
        "operationId": "Preview_ListItemChannels",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item whose publications to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item whose publications to list."
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filters on whether the publication is active.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the publication is active."
            }
          },
          {
            "name": "isFeatured",
            "in": "query",
            "description": "Filters on whether the item is featured in the channel.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the item is featured in the channel."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicItemChannelResponse"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'channels:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "channels:read"
      }
    },
    "/preview/items/{itemNumber}/channels/{channelCode}": {
      "delete": {
        "tags": [
          "Channels"
        ],
        "summary": "Unpublish an item from a channel",
        "description": "Removes the publication, so the item is no longer part of the channel's assortment. This discards the channel-specific content, SEO and slug along with it — to take an item out of the shop while keeping that work, patch isActive to false instead.\n\nRequires the `channels:write` scope.",
        "operationId": "Preview_DeleteItemChannel",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the published item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the published item."
            }
          },
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel to remove it from.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel to remove it from."
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, no channel with that code, or the item is not published on that channel.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'channels:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "channels:write"
      },
      "get": {
        "tags": [
          "Channels"
        ],
        "summary": "Get an item's publication on a channel",
        "description": "Returns the channel-specific content, SEO, stock display and scheduling for one item in one channel. Every content field is null when the channel uses the item's own value. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `channels:read` scope.",
        "operationId": "Preview_GetItemChannel",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the published item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the published item."
            }
          },
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel it is published on.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel it is published on."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemChannelResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, no channel with that code, or the item is not published on that channel. The three are separate errors and the problem detail says which.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'channels:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "channels:read"
      },
      "patch": {
        "tags": [
          "Channels"
        ],
        "summary": "Update an item's publication on a channel",
        "description": "Partially updates one publication. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field — which for the content fields means falling back to the item's own value. isActive, showStock, sortOrder and isFeatured cannot be set to null. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. Changing the slug changes the product's public URL and automatically creates a 301 redirect from the old one, so incoming links and their ranking are preserved. itemNumber and channelCode cannot be changed — they are the resource's address; moving a publication to another channel is a delete and a create.\n\nRequires the `channels:write` scope.",
        "operationId": "Preview_PatchItemChannel",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the published item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the published item."
            }
          },
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel it is published on.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel it is published on."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchItemChannelRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchItemChannelRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a field present in it failed validation, displayCategoryCode names a category that does not exist, or one of isActive, showStock, sortOrder and isFeatured was sent as null.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, no channel with that code, or the item is not published on that channel.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "ItemChannel.SlugNotUnique — another item in the channel already uses that slug.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'channels:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "channels:write"
      }
    },
    "/preview/channels/{channelCode}": {
      "get": {
        "tags": [
          "Channels"
        ],
        "summary": "Get a sales channel by code",
        "description": "Returns the commercial terms that apply when something is sold through this channel: currency, default warehouse, price list and order type. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `channels:read` scope.",
        "operationId": "Preview_GetChannel",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel to read, e.g. webshop-se.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel to read, e.g. webshop-se."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicChannelResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'channels:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "channels:read"
      }
    },
    "/preview/channels/{channelCode}/items": {
      "get": {
        "tags": [
          "Channels"
        ],
        "summary": "List the items published on a channel",
        "description": "The channel's assortment: which items are published, in which order, with the channel-specific texts and SEO that override the item's own. This is the read a storefront builds its catalogue from. Sorted by sort order, then item number and channel code. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200. publishDate and unpublishDate are returned as stored and are not applied by this endpoint — a scheduled publication appears here before it goes live, so filter on them if you are rendering a live catalogue. Delta sync: ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Newly created publications are included even though they have no modifiedDate yet.\n\nRequires the `channels:read` scope.",
        "operationId": "Preview_ListChannelItems",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel whose published items to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel whose published items to list."
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filters on whether the publication is active.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the publication is active."
            }
          },
          {
            "name": "isFeatured",
            "in": "query",
            "description": "Filters on whether the item is featured in the channel.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the item is featured in the channel."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicItemChannelResponse"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'channels:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "channels:read"
      }
    },
    "/preview/channels": {
      "get": {
        "tags": [
          "Channels"
        ],
        "summary": "List sales channels",
        "description": "Returns the sales channels the tenant sells through — webshops, B2B portals, marketplaces and apps — with the commercial terms that apply in each: currency, default warehouse, price list and order type. Sorted by channel code. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200. Filters combine with AND. Enum filters are matched case-insensitively and an unknown value returns 400. A channel carries no presentation — branding, menus and content pages are not part of this contract. What an item looks like in a channel is under GET /preview/channels/{channelCode}/items.\n\nRequires the `channels:read` scope.",
        "operationId": "Preview_ListChannels",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches channel code and name, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches channel code and name, case-insensitively and on partial words."
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filters on whether the channel is active.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the channel is active."
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filters on the kind of channel.",
            "schema": {
              "enum": [
                "B2C",
                "B2B",
                "Marketplace",
                "App",
                "Store"
              ],
              "type": "string",
              "description": "Filters on the kind of channel."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicChannelResponse"
                }
              }
            }
          },
          "400": {
            "description": "The type filter got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'channels:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "channels:read"
      }
    },
    "/preview/configurations/calculate": {
      "post": {
        "tags": [
          "Configurations"
        ],
        "summary": "Price and validate a configuration",
        "description": "Runs the configuration through the same engine and the same price hierarchy a real order uses, without saving anything. Call it on every change while the customer configures.\n\n**This is a live price, not a locked quote.** The order re-prices when the configuration is converted, so the same choices give the same `unitPrice` only while the underlying prices hold: a campaign that starts or expires in between, or an agreement that changes, moves the price. The order also always uses the customer's own currency — a `currencyCode` passed here affects the calculation only. Persisting an agreed price is not supported yet; treat a quoted price as valid for the moment it was calculated.\n\n**An incomplete configuration is not an error.** Missing required values, numbers outside `minValue`/`maxValue` and options that do not belong to their feature all come back as `200` with `isValid: false` and every problem listed in `validationErrors` (`featureCode`, `code`, `message`), so the app can show them at the right field. The price fields are null in that case. Only structural problems — unknown `itemNumber`, `customerNumber`, `featureCode` or `optionCode` — return `400`.\n\n`resolvedValues` carries the derived numbers (area, fabric consumption, …) computed from `Calculated` features, so the app does not have to reimplement the formulas.\n\n`unitPrice` excludes VAT, freight and order-level discounts. Note that a configured line is priced as a manual unit price, so automatic customer discounts (the discount engine) do not apply to it; price lists, agreements, campaigns and volume breaks do. A choice whose option carries a `linkedItemNumber` adds that item to the bill of materials but does **not** change `unitPrice` — see the note on `priceImpact` in the configuration schema.\n\nThis endpoint has no side effects and is the one POST under /preview that does **not** require an `Idempotency-Key` header.\n\nRequires the `configurations:read` scope.",
        "operationId": "Preview_CalculateConfiguration",
        "parameters": [
          {
            "name": "includeBreakdown",
            "in": "query",
            "description": "Also returns components[] (the exploded bill of materials) and operations[] (the production steps). Off by default — that is costing data, and a consumer-facing configurator should not ship it to the browser.",
            "required": true,
            "schema": {
              "type": "boolean",
              "description": "Also returns components[] (the exploded bill of materials) and operations[] (the production steps). Off by default — that is costing data, and a consumer-facing configurator should not ship it to the browser."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CalculateConfigurationRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal — just the item and a quantity",
                  "value": {
                    "itemNumber": "CURTAIN-PLEAT",
                    "quantity": "1"
                  }
                },
                "full": {
                  "summary": "Full — a made-to-measure curtain for a specific customer",
                  "value": {
                    "itemNumber": "CURTAIN-PLEAT",
                    "quantity": "2",
                    "customerNumber": "CUST-001",
                    "currencyCode": "SEK",
                    "values": [
                      {
                        "featureCode": "WIDTH",
                        "number": "240"
                      },
                      {
                        "featureCode": "HEIGHT",
                        "number": "180"
                      },
                      {
                        "featureCode": "FABRIC",
                        "optionCode": "LINEN-NATURAL"
                      },
                      {
                        "featureCode": "LINING",
                        "boolean": true
                      },
                      {
                        "featureCode": "RAIL",
                        "itemNumber": "RAIL-3M"
                      },
                      {
                        "featureCode": "LABEL",
                        "text": "Living room, window 2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicConfigurationCalculationResponse"
                }
              }
            }
          },
          "400": {
            "description": "A structural problem: unknown itemNumber, customerNumber, featureCode or optionCode, or a quantity of zero or less. An incomplete or invalid set of choices is not an error here — it comes back as 200 with isValid: false.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'configurations:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "configurations:read"
      }
    },
    "/preview/configurations": {
      "post": {
        "tags": [
          "Configurations"
        ],
        "summary": "Save a configuration",
        "description": "Persists a set of choices as a configuration and returns it with a `configurationNumber` — the business key for every follow-up call. Use this once the customer has settled on a configuration that POST /preview/configurations/calculate reports as valid; the calculate endpoint is for the live pricing while they are still choosing.\n\nThe configuration is validated on save: a missing required value, a number outside its bounds or an option that does not belong to its feature returns `400` with the error code in the `errors` array (`FeatureExplosion.RequiredFeatureMissing`, `FeatureExplosion.ValueOutOfRange`, `FeatureExplosion.InvalidOption`). Validate with calculate first to get all problems at once.\n\n`customerNumber` is optional here so an anonymous session can be saved and claimed later, but it must be set before POST /preview/configurations/{configurationNumber}/order will succeed. Add it afterwards by passing `customerNumber` to POST /preview/configurations/{configurationNumber}/reconfigure.\n\nThe response carries the priced configuration — `unitPrice` and `totalPrice` alongside the choices.\n\nRequires an `Idempotency-Key` header like every other POST — reuse the same key on a retry to get the original configuration back instead of creating a duplicate.\n\nRequires the `configurations:write` scope.",
        "operationId": "Preview_CreateConfiguration",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateConfigurationRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal — item and quantity only",
                  "value": {
                    "itemNumber": "CURTAIN-PLEAT",
                    "quantity": "1"
                  }
                },
                "full": {
                  "summary": "Full — a measured curtain for a named customer",
                  "value": {
                    "itemNumber": "CURTAIN-PLEAT",
                    "quantity": "2",
                    "customerNumber": "CUST-001",
                    "title": "Living room curtains",
                    "description": "Window 2, measured 2026-07-30",
                    "warehouseCode": "MAIN",
                    "values": [
                      {
                        "featureCode": "WIDTH",
                        "number": "240"
                      },
                      {
                        "featureCode": "HEIGHT",
                        "number": "180"
                      },
                      {
                        "featureCode": "FABRIC",
                        "optionCode": "LINEN-NATURAL"
                      },
                      {
                        "featureCode": "LINING",
                        "boolean": true
                      },
                      {
                        "featureCode": "RAIL",
                        "itemNumber": "RAIL-3M"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicConfigurationResponse"
                }
              }
            }
          },
          "400": {
            "description": "A required value is missing, a number falls outside its bounds, an option does not belong to its feature, or the itemNumber, customerNumber or warehouseCode does not exist.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'configurations:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "configurations:write"
      },
      "get": {
        "tags": [
          "Configurations"
        ],
        "summary": "List saved configurations",
        "description": "Returns the configurations that have not yet become orders, oldest configuration number first.\n\nA configuration disappears from this list once POST /preview/configurations/{configurationNumber}/order has turned it into a sales order — from that point it is an order and is read through GET /preview/orders instead.\n\n?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. \n\nDeletions are not visible here: a deleted record is really gone, so it simply stops appearing, which is indistinguishable from \"unchanged\". Poll GET /preview/deletions?deletedSince= alongside this endpoint to learn what was removed. \n\n**One removal still has no tombstone: being ordered.** A configuration that has become a sales order is not deleted — it stops matching this list because it is now an order, so it appears in neither the delta nor GET /preview/deletions. Record the `orderNumber` from the response to the /order call, or reconcile against GET /preview/orders, to retire those local copies.\n\nThe price fields (`unitPrice`, `totalPrice`, …) are **null** in this list — pricing a whole page would mean one price engine run per row. Read a single configuration, or use POST /preview/configurations/calculate, when you need prices.\n\nPaginated response: `{ items, totalCount, page, pageSize, totalPages, hasPreviousPage, hasNextPage }`. `?page=` defaults to 1, `?pageSize=` to 50 and is capped at 200.\n\nRequires the `configurations:read` scope.",
        "operationId": "Preview_ListConfigurations",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches configuration number, title and description, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches configuration number, title and description, case-insensitively and on partial words."
            }
          },
          {
            "name": "customerNumber",
            "in": "query",
            "description": "Returns only the configurations saved for this customer number.",
            "schema": {
              "type": "string",
              "description": "Returns only the configurations saved for this customer number."
            }
          },
          {
            "name": "itemNumber",
            "in": "query",
            "description": "Returns only the configurations of this configurable item.",
            "schema": {
              "type": "string",
              "description": "Returns only the configurations of this configurable item."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicConfigurationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'configurations:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "configurations:read"
      }
    },
    "/preview/configurations/{configurationNumber}/order": {
      "post": {
        "tags": [
          "Configurations"
        ],
        "summary": "Turn a configuration into a sales order",
        "description": "Creates a sales order with a single line for the configured product, priced at base price plus configuration surcharge through the same price hierarchy POST /preview/configurations/calculate uses. The response is the same representation as GET /preview/orders/{orderNumber}, with the canonical URL in the `Location` header.\n\nThe line is priced **now**, not from a stored quote: the price engine runs again at conversion, in the customer's own currency. Unchanged choices give the calculated price as long as the underlying prices still hold — a campaign starting or expiring in between will move it.\n\nThe order is created in Draft. Add freight, extra lines or a delivery address through the order endpoints, then place it with POST /preview/orders/{orderNumber}/place. Behind the line, the configuration becomes a production work order carrying the exploded bill of materials and routing.\n\nThe configuration itself is consumed: it stops appearing in GET /preview/configurations and its own GET returns `404` afterwards. Store the `orderNumber` from this response — it is the only link back to the configuration you just converted.\n\nKnown error codes: `409 WorkOrder.NotEstimate` — already ordered. `409 WorkOrder.NoCustomer` — the configuration has no customer; attach one by passing `customerNumber` to reconfigure first. `409 WorkOrder.NoOutputItem` — the configuration has no item. `400 Warehouse.NoDefault` and `400 OrderType.NoDefault` — the tenant has no default warehouse or order type configured; that is a setup problem in Fluit, not something the request can fix.\n\nNote that the line is priced as a manual unit price, so automatic customer discounts do not apply to it. Price lists, agreements, campaigns and volume breaks are already reflected in the base price.\n\nRequires the `configurations:write` scope.",
        "operationId": "Preview_CreateOrderFromConfiguration",
        "parameters": [
          {
            "name": "configurationNumber",
            "in": "path",
            "description": "Configuration number of the saved configuration to turn into an order.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Configuration number of the saved configuration to turn into an order."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOrderFromConfigurationRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "No body — order with an open delivery date",
                  "value": { }
                },
                "full": {
                  "summary": "With a requested delivery date",
                  "value": {
                    "requestedDeliveryDate": "2026-09-15"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicOrderDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "The tenant has no default warehouse or no default order type configured, so the order cannot be created. That is a setup problem in Fluit, not something the request can fix.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No configuration with that configuration number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The configuration has already become an order, has no customer attached, or has no item.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'configurations:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "configurations:write"
      }
    },
    "/preview/configurations/{configurationNumber}": {
      "delete": {
        "tags": [
          "Configurations"
        ],
        "summary": "Discard a configuration",
        "description": "Deletes a configuration that was never ordered. A configurator produces a lot of abandoned configurations, and this is how the app cleans them up instead of leaving them in the tenant's list.\n\nReturns `409` (`Configuration.NotConfigurable`) once the configuration has become an order — what sits behind the order line is production data and is not deletable through this API. Cancel the order with POST /preview/orders/{orderNumber}/cancel instead.\n\nRequires the `configurations:write` scope.",
        "operationId": "Preview_DeleteConfiguration",
        "parameters": [
          {
            "name": "configurationNumber",
            "in": "path",
            "description": "Configuration number of the configuration to discard.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Configuration number of the configuration to discard."
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No configuration with that configuration number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The configuration has become an order and can no longer be discarded.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'configurations:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "configurations:write"
      },
      "get": {
        "tags": [
          "Configurations"
        ],
        "summary": "Get a saved configuration",
        "description": "Returns one configuration with its chosen values, resolved to feature and option codes, and priced for its customer — `basePricePerUnit`, `configurationSurchargePerUnit`, `unitPrice` and `totalPrice`. Use it to resume a saved configuration without replaying the values through POST /preview/configurations/calculate.\n\nReturns `404` once the configuration has become an order — a configuration only exists until it is ordered. Read the resulting order through GET /preview/orders/{orderNumber} instead, using the order number from the response to POST /preview/configurations/{configurationNumber}/order.\n\nThe price is calculated on read, so it reflects today's price lists and campaigns rather than what was quoted when the configuration was saved. The price fields are omitted if the saved configuration can no longer be priced (e.g. the item's features have changed since).\n\nResponses carry a weak ETag; pass it back in `If-None-Match` to get `304 Not Modified` while the response is unchanged. The validator is derived from the response itself, so it covers the calculated price too: if today's price differs from the one in your cached copy you get a fresh `200`, not a `304`.\n\nRequires the `configurations:read` scope.",
        "operationId": "Preview_GetConfiguration",
        "parameters": [
          {
            "name": "configurationNumber",
            "in": "path",
            "description": "Configuration number of the saved configuration to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Configuration number of the saved configuration to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicConfigurationResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No configuration with that configuration number, including one that has become an order.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'configurations:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "configurations:read"
      }
    },
    "/preview/items/{itemNumber}/configuration": {
      "get": {
        "tags": [
          "Configurations"
        ],
        "summary": "Get an item's configuration schema",
        "description": "Returns everything needed to render a configurator form for one item: its configurable features, their input types, bounds, defaults and price impact, plus the allowed options for each selection. This is the first call in the configurator flow.\n\nEach feature's `featureType` decides which field to send back in `values[]`: `Text` → `text`, `Number` → `number` (bounded by `minValue`/`maxValue`), `Selection` → `optionCode`, `Boolean` → `boolean`, `ItemSelection` → `itemNumber`. `Calculated` features take no input — they are derived from the others and their results come back in `resolvedValues` from POST /preview/configurations/calculate.\n\n`features` is not paginated: a configurator cannot render a half-loaded form, so the whole schema always ships in one response. An item with no configurable features returns `isConfigurable: false` and an empty list — filter GET /preview/items with `?isConfigurable=true` to find the configurable ones. Prices here are the tenant base-currency list prices; use POST /preview/configurations/calculate for the real, customer-specific price of a given set of choices. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `configurations:read` scope.",
        "operationId": "Preview_GetItemConfiguration",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the product to read the configuration schema for.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the product to read the configuration schema for."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemConfigurationResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'configurations:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "configurations:read"
      }
    },
    "/preview/configurations/{configurationNumber}/reconfigure": {
      "post": {
        "tags": [
          "Configurations"
        ],
        "summary": "Change a saved configuration",
        "description": "Changes a saved configuration and re-runs the engine.\n\nEvery field is optional and omitting one leaves that part alone:\n- `values` **omitted** keeps the current choices — that is how you change only the quantity. When present it is a **full replacement**, not a patch: anything not in the list is cleared, and an empty array clears every choice.\n- `quantity` omitted keeps the current quantity.\n- `customerNumber` omitted keeps the current customer. Set it to claim a configuration that was saved anonymously — a configuration must have a customer before it can be ordered.\n\nReturns `200` with the updated configuration, including the recalculated `unitPrice`, rather than `204`. That is a deliberate departure from the usual action-endpoint convention — the whole point of reconfiguring is the new result, and forcing a follow-up GET for it would be wasteful.\n\nReturns `409` (`Configuration.NotConfigurable`) once the configuration has become an order: an ordered configuration is frozen, since changing it would silently change what the customer bought. The status is checked before the body, so an ordered configuration returns the conflict regardless of what the payload contains. Change the order line instead, or create a new configuration.\n\nInvalid values return `400` with the offending `FeatureExplosion.*` code. Use POST /preview/configurations/calculate first to see all problems at once.\n\nRequires the `configurations:write` scope.",
        "operationId": "Preview_ReconfigureConfiguration",
        "parameters": [
          {
            "name": "configurationNumber",
            "in": "path",
            "description": "Configuration number of the configuration to change.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Configuration number of the configuration to change."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReconfigureConfigurationRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Change the quantity only — the choices are kept",
                  "value": {
                    "quantity": "3"
                  }
                },
                "claim": {
                  "summary": "Attach a customer to an anonymously saved configuration",
                  "value": {
                    "customerNumber": "CUST-001"
                  }
                },
                "full": {
                  "summary": "New measurements and a different fabric",
                  "value": {
                    "quantity": "2",
                    "values": [
                      {
                        "featureCode": "WIDTH",
                        "number": "260"
                      },
                      {
                        "featureCode": "HEIGHT",
                        "number": "180"
                      },
                      {
                        "featureCode": "FABRIC",
                        "optionCode": "VELVET-DEEPBLUE"
                      },
                      {
                        "featureCode": "LINING",
                        "boolean": true
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicConfigurationResponse"
                }
              }
            }
          },
          "400": {
            "description": "A chosen value is invalid: a required feature is missing, a number falls outside its bounds, an option does not belong to its feature, or the quantity is zero or less.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No configuration with that configuration number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The configuration has become an order and is frozen, or it has no item to configure.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'configurations:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "configurations:write"
      }
    },
    "/preview/channels/{channelCode}/content-pages": {
      "post": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Create a content page",
        "description": "Creates a standing page, a blog post or a news item, told apart by pageType. The page is created unpublished and with no sections; add the body with PUT /preview/channels/{channelCode}/content-pages/{slug}/config and make it visible with POST .../publish. publishDate may be in the future to schedule an article. The response body is the same representation as GET on the page; the canonical URL is returned in the Location header and in links.self.\n\nRequires the `content-pages:write` scope.",
        "operationId": "Preview_CreateContentPage",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel to create the page in.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel to create the page in."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContentPageRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal — a standing page",
                  "value": {
                    "slug": "om-oss",
                    "title": "Om oss"
                  }
                },
                "full": {
                  "summary": "Full — a scheduled blog post",
                  "value": {
                    "slug": "nya-hogtalarserien",
                    "title": "Nya högtalarserien är här",
                    "pageType": "BlogPost",
                    "metaDescription": "Vi släpper en ny serie aktiva högtalare för konferensrum.",
                    "excerpt": "Fyra modeller, samma DSP-plattform.",
                    "featuredImageUrl": "https://cdn.fluit.cloud/media/hero/abc.jpg",
                    "authorName": "Redaktionen",
                    "publishDate": "2026-09-15T08:00:00Z",
                    "tags": [
                      "produktnyhet",
                      "ljud"
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicContentPageResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, or parentSlug names a page that does not exist in this channel.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "A page with that slug already exists in the channel.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:write"
      },
      "get": {
        "tags": [
          "ContentPages"
        ],
        "summary": "List a channel's content pages",
        "description": "Returns the channel's editorial pages: standing pages, blog posts and news. All three are the same record told apart by pageType, so one call can fetch everything or be narrowed with ?pageType=. Sorted by sort order, then slug. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200. Each page carries its full section list under config, with products, categories and suppliers named by business key rather than internal id. publishDate may be in the future: the storefront hides such an article until it passes, but this endpoint returns it either way. Delta sync: ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Deletions are not visible here: a deleted record is really gone, so it simply stops appearing, which is indistinguishable from \"unchanged\". Poll GET /preview/deletions?deletedSince= alongside this endpoint to learn what was removed. \n\nRequires the `content-pages:read` scope.",
        "operationId": "Preview_ListContentPages",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel whose pages to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel whose pages to list."
            }
          },
          {
            "name": "pageType",
            "in": "query",
            "description": "Filters on the kind of page: Page, BlogPost or NewsPost.",
            "schema": {
              "enum": [
                "Page",
                "BlogPost",
                "NewsPost",
                "Home"
              ],
              "type": "string",
              "description": "Filters on the kind of page: Page, BlogPost or NewsPost."
            }
          },
          {
            "name": "isPublished",
            "in": "query",
            "description": "Filters on whether the page is published.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the page is published."
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Matches slug and title, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches slug and title, case-insensitively and on partial words."
            }
          },
          {
            "name": "tag",
            "in": "query",
            "description": "Returns only pages carrying this tag, matched case-insensitively. Applied before paging, so totalCount counts the tagged pages and page 1 is never empty while later pages hold matches.",
            "schema": {
              "type": "string",
              "description": "Returns only pages carrying this tag, matched case-insensitively. Applied before paging, so totalCount counts the tagged pages and page 1 is never empty while later pages hold matches."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicContentPageResponse"
                }
              }
            }
          },
          "400": {
            "description": "pageType got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:read"
      }
    },
    "/preview/channels/{channelCode}/content-pages/{slug}": {
      "delete": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Delete a content page",
        "description": "Removes the page and its sections for good. To take a page down while keeping its content, use POST .../unpublish instead. A page with child pages cannot be deleted: move the children to another parent or delete them first. The deletion is reported under GET /preview/deletions as the resource content-pages, with the business key {channelCode}/{slug}, so a client syncing on ?modifiedSince= learns the page is gone.\n\nRequires the `content-pages:write` scope.",
        "operationId": "Preview_DeleteContentPage",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the page belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the page belongs to."
            }
          },
          {
            "name": "slug",
            "in": "path",
            "description": "The page's slug within that channel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The page's slug within that channel."
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no page with that slug in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "ContentPage.HasChildPages — the page still has child pages.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:write"
      },
      "get": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Get a content page by slug",
        "description": "Returns the page with its full section list. Products, categories and suppliers inside the sections are named by business key — item number, category code, supplier number — so the same body can be written back. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the page is unchanged.\n\nRequires the `content-pages:read` scope.",
        "operationId": "Preview_GetContentPage",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the page belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the page belongs to."
            }
          },
          {
            "name": "slug",
            "in": "path",
            "description": "The page's slug within that channel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The page's slug within that channel."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicContentPageResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no page with that slug in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:read"
      },
      "patch": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Update a content page's metadata",
        "description": "Partially updates the page's title, SEO, navigation and article fields. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. tags replaces the whole list rather than merging into it. The sections are not touched here — use PUT .../config for the body. Renaming the slug with newSlug changes the page's public URL and automatically creates a 301 redirect from the old one, so incoming links and their ranking are preserved. Changing pageType does the same, because it moves the page between the /blog/... and /pages/... URL families.\n\nRequires the `content-pages:write` scope.",
        "operationId": "Preview_PatchContentPage",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the page belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the page belongs to."
            }
          },
          {
            "name": "slug",
            "in": "path",
            "description": "The page's slug within that channel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The page's slug within that channel."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchContentPageRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchContentPageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a field present in it failed validation, parentSlug names a page that does not exist in this channel, or one of newSlug, title, sortOrder, showInNavigation and pageType was sent as null.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no page with that slug in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "newSlug is already taken by another page in the channel.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:write"
      }
    },
    "/preview/channels/{channelCode}/home-page": {
      "get": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Read a channel's home page",
        "description": "Returns the section list the storefront renders at the channel's root. The home page is not a content page: there is exactly one per channel, it has no slug, and it cannot be unpublished or deleted — which is why it is addressed by channel code alone. The body is the same config a content page carries, with the same section types and the same business-key references, so one renderer covers both. Replace it with PUT on the same URL. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the home page is unchanged.\n\nRequires the `content-pages:read` scope.",
        "operationId": "Preview_GetChannelHomePage",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel whose home page to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel whose home page to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicChannelHomePageResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or the channel has no storefront configuration yet (StorefrontConfig.NotFound).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:read"
      },
      "put": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Replace a channel's home page",
        "description": "Replaces the home page: layout, full-width flag and the whole section list. This is a PUT and not a PATCH because the section list is positional — sending a subset would be ambiguous between \"these are the sections now\" and \"merge these in\". Read the home page, change what you need, send the whole config back. Keep each section's id when you do: an omitted id creates a new section, so dropping them would replace every section with a copy and lose their identity. This replaces the whole config, so send every field you want kept: an omitted layout or fullWidth falls back to its default rather than to the stored value. sections has no default and must be present — send [] to clear the page deliberately, so that a body carrying only layout cannot wipe it by accident. Products, categories and suppliers are named by business key. An unknown key is rejected with 400 rather than dropped, so a section cannot silently lose half its products. Returns the whole home page, the same representation as GET, so the caller sees the result without a second request. No Idempotency-Key is needed — the header is required on POST. Repeating the same body is safe as long as the sections carry their ids; sections sent without one are created afresh on every call.\n\nRequires the `content-pages:write` scope.",
        "operationId": "Preview_PutChannelHomePage",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel whose home page to replace.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel whose home page to replace."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicPageConfig"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicChannelHomePageResponse"
                }
              }
            }
          },
          "400": {
            "description": "A section referenced an item number, category code or supplier number that does not exist, or two sections carried the same id. The error names the section and the field, e.g. sections[2].productNumbers[0]. Also when a section omitted a field its own type requires: a SharedSections section without sectionCollectionId is rejected as sections[{index}].sectionCollectionId.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or the channel has no storefront configuration yet (StorefrontConfig.NotFound).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:write"
      }
    },
    "/preview/channels/{channelCode}/content-pages/{slug}/publish": {
      "post": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Publish a content page",
        "description": "Marks the page published and stamps publishedAt. Publishing an already published page is harmless and leaves the original publishedAt alone. An article whose publishDate is still in the future stays hidden in the storefront until that date passes, even once published here.\n\nRequires the `content-pages:write` scope.",
        "operationId": "Preview_PublishContentPage",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the page belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the page belongs to."
            }
          },
          {
            "name": "slug",
            "in": "path",
            "description": "The page's slug within that channel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The page's slug within that channel."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no page with that slug in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:write"
      }
    },
    "/preview/channels/{channelCode}/content-pages/{slug}/config": {
      "put": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Replace a content page's sections",
        "description": "Replaces the page body: layout, full-width flag and the whole section list. This is a PUT and not a PATCH because the section list is positional — sending a subset would be ambiguous between \"these are the sections now\" and \"merge these in\". Read the page, change what you need, send the whole config back. Keep each section's id when you do: an omitted id creates a new section, so dropping them would replace every section with a copy and lose their identity. This replaces the whole config, so send every field you want kept: an omitted layout or fullWidth falls back to its default rather than to the stored value. sections has no default and must be present — send [] to clear the body deliberately. Products, categories and suppliers are named by business key. An unknown key is rejected with 400 rather than dropped, so a section cannot silently lose half its products. Returns the whole page, the same representation as GET, so the caller sees the result without a second request. No Idempotency-Key is needed — the header is required on POST. Repeating the same body is safe as long as the sections carry their ids; sections sent without one are created afresh on every call.\n\nRequires the `content-pages:write` scope.",
        "operationId": "Preview_PutContentPageConfig",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the page belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the page belongs to."
            }
          },
          {
            "name": "slug",
            "in": "path",
            "description": "The page's slug within that channel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The page's slug within that channel."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicPageConfig"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicContentPageResponse"
                }
              }
            }
          },
          "400": {
            "description": "A section referenced an item number, category code or supplier number that does not exist. The error names the section and the field, e.g. sections[2].productNumbers[0]. Also when a section omitted a field its own type requires: a SharedSections section without sectionCollectionId is rejected as sections[{index}].sectionCollectionId.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no page with that slug in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:write"
      }
    },
    "/preview/channels/{channelCode}/content-pages/{slug}/unpublish": {
      "post": {
        "tags": [
          "ContentPages"
        ],
        "summary": "Unpublish a content page",
        "description": "Hides the page from the storefront without deleting it. The sections, SEO and slug are kept, so publishing it again restores exactly what was there. Use this rather than DELETE to take something down temporarily.\n\nRequires the `content-pages:write` scope.",
        "operationId": "Preview_UnpublishContentPage",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the page belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the page belongs to."
            }
          },
          {
            "name": "slug",
            "in": "path",
            "description": "The page's slug within that channel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The page's slug within that channel."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no page with that slug in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'content-pages:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "content-pages:write"
      }
    },
    "/preview/customers": {
      "post": {
        "tags": [
          "Customers"
        ],
        "summary": "Create a customer",
        "description": "Creates a new customer for the authenticated tenant. Customer number is auto-generated if not provided. defaultBackorderBehavior controls what happens to unfulfillable quantities on this customer's orders; omit it to use CreateBackorder. Allowed values: CreateBackorder, CancelRemaining, HoldOrder. The response body is the same representation as GET /preview/customers/{customerNumber}; the canonical URL is returned in the Location header and in links.self.\n\nRequires the `customers:write` scope.",
        "operationId": "Preview_CreateCustomer",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomerRequest"
              },
              "examples": {
                "default": {
                  "summary": "Create customer",
                  "value": {
                    "name": "Acme AB",
                    "customerNumber": "CUST-001",
                    "organizationNumber": "5560001234",
                    "invoiceEmail": "invoice@acme.se",
                    "phone": "+46701234567",
                    "street1": "Storgatan 1",
                    "postalCode": "11122",
                    "city": "Stockholm",
                    "countryCode": "SE"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCustomerResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, for example an invalid email address or a field over its maximum length.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'customers:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "customers:write"
      },
      "get": {
        "tags": [
          "Customers"
        ],
        "summary": "List customers",
        "description": "Returns a paginated list of customers for the authenticated tenant. Sorted by customer number. ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Deletions are not visible here: a deleted record is really gone, so it simply stops appearing, which is indistinguishable from \"unchanged\". Poll GET /preview/deletions?deletedSince= alongside this endpoint to learn what was removed. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `customers:read` scope.",
        "operationId": "Preview_ListCustomers",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches customer number, name, organisation number and email, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches customer number, name, organisation number and email, case-insensitively and on partial words."
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filters on whether the customer is active. Inactive customers cannot be placed on new orders.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the customer is active. Inactive customers cannot be placed on new orders."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicCustomerResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'customers:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "customers:read"
      }
    },
    "/preview/customers/{customerNumber}": {
      "get": {
        "tags": [
          "Customers"
        ],
        "summary": "Get a customer by customer number",
        "description": "Returns the details of a customer belonging to the authenticated tenant. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged. The validator follows the whole record, so a change to a nested part invalidates it too.\n\nRequires the `customers:read` scope.",
        "operationId": "Preview_GetCustomer",
        "parameters": [
          {
            "name": "customerNumber",
            "in": "path",
            "description": "Customer number of the customer to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Customer number of the customer to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCustomerResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No customer with that customer number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'customers:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "customers:read"
      },
      "patch": {
        "tags": [
          "Customers"
        ],
        "summary": "Update a customer",
        "description": "Partially updates a customer. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts.\n\nRequires the `customers:write` scope.",
        "operationId": "Preview_PatchCustomer",
        "parameters": [
          {
            "name": "customerNumber",
            "in": "path",
            "description": "Customer number of the customer to update.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Customer number of the customer to update."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchCustomerRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchCustomerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, or a field present in it failed validation.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No customer with that customer number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'customers:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "customers:write"
      }
    },
    "/preview/customers/{customerNumber}/addresses": {
      "get": {
        "tags": [
          "Customers"
        ],
        "summary": "List customer delivery addresses",
        "description": "Returns a paginated list of the delivery addresses registered on the customer, default address first. Use the fields to populate deliveryAddress when creating orders. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `customers:read` scope.",
        "operationId": "Preview_ListCustomerAddresses",
        "parameters": [
          {
            "name": "customerNumber",
            "in": "path",
            "description": "Customer number of the customer whose addresses to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Customer number of the customer whose addresses to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicCustomerAddressResponse"
                }
              }
            }
          },
          "404": {
            "description": "No customer with that customer number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'customers:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "customers:read"
      }
    },
    "/preview/customers/{customerNumber}/contacts": {
      "get": {
        "tags": [
          "Customers"
        ],
        "summary": "List customer contacts",
        "description": "Returns a paginated list of the contact persons registered on the customer, default contact first. Use a contact's id as customerContactId when creating orders. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `customers:read` scope.",
        "operationId": "Preview_ListCustomerContacts",
        "parameters": [
          {
            "name": "customerNumber",
            "in": "path",
            "description": "Customer number of the customer whose contacts to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Customer number of the customer whose contacts to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicCustomerContactResponse"
                }
              }
            }
          },
          "404": {
            "description": "No customer with that customer number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'customers:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "customers:read"
      }
    },
    "/preview/inventory/counts/{countNumber}/apply": {
      "post": {
        "tags": [
          "Inventory"
        ],
        "summary": "Apply an inventory count",
        "description": "Posts the counted differences to stock: every line whose counted quantity differs from the recorded one produces an Adjustment movement in the ledger, and the count moves to Applied. Returns the count so the caller can see the posted variance without a second request. This is irreversible — the resulting movements can only be undone by counting again or adjusting manually. The count must be Completed; applying a Draft or InProgress count returns 409, as does applying one that is already Applied. Read the resulting movements from GET /preview/inventory/transactions with ?transactionType=Adjustment.\n\nRequires the `inventory:write` scope.",
        "operationId": "Preview_ApplyInventoryCount",
        "parameters": [
          {
            "name": "countNumber",
            "in": "path",
            "description": "Count number of the inventory count to post to stock.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Count number of the inventory count to post to stock."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicInventoryCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "The count still has uncounted lines, or it has no lines at all.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No inventory count with that count number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The count is not Completed — a Draft or InProgress count has nothing final to post, and an Applied count has already been posted.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:write"
      }
    },
    "/preview/inventory/batches": {
      "get": {
        "tags": [
          "Inventory"
        ],
        "summary": "List batches",
        "description": "Lists batches (lots) with expiry, status and current stock, sorted by expiry date so the batch that expires first comes first. Filter with itemNumber for a single article, batchNumber to search by lot number (also matches the supplier's own lot number), expiringWithinDays to find batches close to expiry, and inStockOnly to skip batches without remaining stock. Check IsPickable before selling from a batch — a blocked, quarantined, recalled or expired batch reports false.\n\nRequires the `inventory:read` scope.",
        "operationId": "Preview_ListBatches",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "batchNumber",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expiringWithinDays",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "inStockOnly",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_BatchesPublicBatchResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:read"
      }
    },
    "/preview/inventory/items/{itemNumber}/batches/{batchNumber}/trace": {
      "get": {
        "tags": [
          "Inventory"
        ],
        "summary": "Trace a batch",
        "description": "Returns where a batch came from and which customers received it — one step back and one step forward. Use this to answer a recall question from an external system: given a lot number, which sales orders and customers are affected. DeliveredTo lists one entry per sales order with the quantity that order received. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `inventory:read` scope.",
        "operationId": "Preview_TraceBatch",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "batchNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchesPublicBatchTraceResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:read"
      }
    },
    "/preview/inventory/items/{itemNumber}/batches/{batchNumber}/block": {
      "post": {
        "tags": [
          "Inventory"
        ],
        "summary": "Block a batch",
        "description": "Blocks a batch so it can no longer be allocated or picked. Use this when an external quality system rejects a lot. The block applies to every location holding the batch. Blocking an already rejected batch returns 400.\n\nRequires the `inventory:write` scope.",
        "operationId": "Preview_BlockBatch",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "batchNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchesBlockBatchRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:write"
      }
    },
    "/preview/inventory/adjustments": {
      "post": {
        "tags": [
          "Inventory"
        ],
        "summary": "Adjust stock at a location",
        "description": "Books a manual stock movement and returns the resulting ledger entry in the same shape as GET /preview/inventory/transactions/{transactionId}, so the balance after the movement is readable without a second request. quantity is a signed delta, not a target balance: -3 writes off three units, +3 adds three. Zero is rejected. transactionType defaults to Adjustment; Scrap is the other allowed value and always reduces stock, so it requires a negative quantity. Receipt, Issue and Transfer belong to the purchase, picking and transfer flows and are rejected here — booking them without their counterpart would leave the ledger inconsistent with the documents behind it. Returning goods to stock is done through the return flow, POST /preview/returns/{returnNumber}/receive. The movement is booked at the location's current average cost; there is no way to set a cost here, because neither an adjustment nor a scrap revalues stock. Use a revaluation for that. Reducing below the quantity on hand at that location returns 409. Known error codes: Item.NotFound, Warehouse.NotFound, WarehouseLocation.NotFound, Inventory.InsufficientStock, Inventory.NoStockAtLocation.\n\nRequires the `inventory:write` scope.",
        "operationId": "Preview_CreateInventoryAdjustment",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInventoryAdjustmentRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Write off three units",
                  "value": {
                    "itemNumber": "ART-1001",
                    "warehouseCode": "HUVUD",
                    "locationCode": "A-01-01",
                    "quantity": "-3",
                    "notes": "Damaged in handling"
                  }
                },
                "full": {
                  "summary": "Scrap one unit",
                  "value": {
                    "itemNumber": "ART-1001",
                    "warehouseCode": "HUVUD",
                    "locationCode": "A-01-01",
                    "quantity": "-1",
                    "transactionType": "Scrap",
                    "notes": "Quality inspection reject, NCR-2026-0042"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicInventoryTransactionResponse"
                }
              }
            }
          },
          "400": {
            "description": "The quantity is zero, a Scrap was sent with a positive quantity, the transaction type may not be booked manually, the item, warehouse or location does not exist, or the adjustment would take the location below zero.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:write"
      }
    },
    "/preview/inventory/counts": {
      "post": {
        "tags": [
          "Inventory"
        ],
        "summary": "Create an inventory count",
        "description": "Creates a physical inventory count and generates its lines from the chosen type and filters. Returns it in the same shape as GET /preview/inventory/counts/{countNumber}. type must be Full, Location, Category, Random or Impulse. Each type has a required companion field: Location takes zoneFilter or locationCodeFilter, Category takes categoryCode, Random takes randomSampleSize and Impulse takes itemNumber. ABC counts are not available through this API yet — the selection is not implemented server-side, and exposing it would produce a count covering the whole warehouse rather than the chosen class. The count starts in Draft; set autoStart=true to go straight to InProgress. Counting itself happens in the warehouse app — this API creates the count and, once it is Completed, posts the differences with POST /preview/inventory/counts/{countNumber}/apply. blindCount=true (the default) hides the recorded quantity from the counter, which is what makes the count independent evidence rather than a confirmation of what the system already believes. Known error codes: Warehouse.NotFound, Item.NotFound, InventoryCount.NoLinesGenerated.\n\nRequires the `inventory:write` scope.",
        "operationId": "Preview_CreateInventoryCount",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInventoryCountRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Full count of a warehouse",
                  "value": {
                    "warehouseCode": "HUVUD",
                    "type": "Full"
                  }
                },
                "full": {
                  "summary": "Zone count, started immediately",
                  "value": {
                    "warehouseCode": "HUVUD",
                    "type": "Location",
                    "zoneFilter": "A",
                    "description": "Quarterly count, zone A",
                    "blindCount": true,
                    "autoStart": true
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicInventoryCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "The count type is not available through this API, the field that type requires is missing, or the warehouse, item or category does not exist.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:write"
      },
      "get": {
        "tags": [
          "Inventory"
        ],
        "summary": "List inventory counts",
        "description": "Returns a paginated list of physical inventory counts, sorted by countNumber. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `inventory:read` scope.",
        "operationId": "Preview_ListInventoryCounts",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filters on how far the count has got.",
            "schema": {
              "enum": [
                "Draft",
                "InProgress",
                "Completed",
                "Applied",
                "Cancelled"
              ],
              "type": "string",
              "description": "Filters on how far the count has got."
            }
          },
          {
            "name": "warehouseCode",
            "in": "query",
            "description": "Returns only the counts made in this warehouse.",
            "schema": {
              "type": "string",
              "description": "Returns only the counts made in this warehouse."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicInventoryCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:read"
      }
    },
    "/preview/inventory/movements": {
      "post": {
        "tags": [
          "Inventory"
        ],
        "summary": "Move stock between locations",
        "description": "Relocates stock within one warehouse and returns the resulting balances at both locations. Returns 200 rather than 201 because a move produces two ledger entries rather than one addressable resource — read them back from GET /preview/inventory/transactions with ?transactionType=Transfer. Both locations must belong to warehouseCode; moving between warehouses is a transfer order, not a movement. Set moveAllocations=true when relocating stock that is already allocated to orders — otherwise the allocations keep pointing at the source location and picking will fail there. Known error codes: Item.NotFound, Warehouse.NotFound, WarehouseLocation.NotFound, Inventory.InsufficientStock.\n\nRequires the `inventory:write` scope.",
        "operationId": "Preview_CreateInventoryMovement",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInventoryMovementRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Move ten units",
                  "value": {
                    "itemNumber": "ART-1001",
                    "warehouseCode": "HUVUD",
                    "fromLocationCode": "INKOMMANDE",
                    "toLocationCode": "A-01-01",
                    "quantity": "10"
                  }
                },
                "full": {
                  "summary": "Move allocated batch-tracked stock",
                  "value": {
                    "itemNumber": "ART-1001",
                    "warehouseCode": "HUVUD",
                    "fromLocationCode": "A-01-01",
                    "toLocationCode": "PLOCK-03",
                    "quantity": "4",
                    "moveAllocations": true,
                    "batchNumber": "L-2026-14",
                    "notes": "Replenish pick face"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateInventoryMovementResponse"
                }
              }
            }
          },
          "400": {
            "description": "Source and destination location are the same, the item, warehouse or either location does not exist, or the source location does not hold that quantity.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:write"
      }
    },
    "/preview/inventory/counts/{countNumber}": {
      "get": {
        "tags": [
          "Inventory"
        ],
        "summary": "Get an inventory count by count number",
        "description": "Returns a physical inventory count with its progress: how many lines exist, how many have been counted, how many differ from the recorded quantity and what those differences are worth. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `inventory:read` scope.",
        "operationId": "Preview_GetInventoryCount",
        "parameters": [
          {
            "name": "countNumber",
            "in": "path",
            "description": "Count number of the inventory count to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Count number of the inventory count to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicInventoryCountResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No inventory count with that count number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:read"
      }
    },
    "/preview/inventory/transactions/{transactionId}": {
      "get": {
        "tags": [
          "Inventory"
        ],
        "summary": "Read a stock movement",
        "description": "Returns one entry from the stock ledger. This is the only resource on the public API addressed by an internal id rather than a business key: a ledger entry has no number of its own — it is identified by the movement it records. The id is the transactionId returned by POST /preview/inventory/adjustments and carried by every row in GET /preview/inventory/transactions. Movements are never modified or deleted after the fact, so a 200 here is stable and safe to cache indefinitely. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `inventory:read` scope.",
        "operationId": "Preview_GetInventoryTransaction",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "description": "Id of the ledger entry, as returned in transactionId by the adjustment and transaction list endpoints.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Id of the ledger entry, as returned in transactionId by the adjustment and transaction list endpoints.",
              "format": "uuid"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicInventoryTransactionResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No stock movement with that id.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:read"
      }
    },
    "/preview/inventory/transactions": {
      "get": {
        "tags": [
          "Inventory"
        ],
        "summary": "Read the stock ledger",
        "description": "Returns stock movements oldest first, which is the order they should be applied in when mirroring the ledger into another system. Quantity is signed: positive increases stock, negative decreases it. For incremental reads, page with ?since= and deduplicate on transactionId — movements are never modified or deleted after the fact, so the ledger only ever grows. Sorting is by transactionDate then id, so paging stays deterministic when several movements share a timestamp. Costs are in the tenant's base currency. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `inventory:read` scope.",
        "operationId": "Preview_ListInventoryTransactions",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "query",
            "description": "Returns only the movements of this item.",
            "schema": {
              "type": "string",
              "description": "Returns only the movements of this item."
            }
          },
          {
            "name": "warehouseCode",
            "in": "query",
            "description": "Returns only the movements booked in this warehouse.",
            "schema": {
              "type": "string",
              "description": "Returns only the movements booked in this warehouse."
            }
          },
          {
            "name": "transactionType",
            "in": "query",
            "description": "Filters on what kind of movement it is.",
            "schema": {
              "enum": [
                "Receipt",
                "Issue",
                "Adjustment",
                "Transfer",
                "Return",
                "Scrap",
                "ConsignmentConsumption",
                "Revaluation"
              ],
              "type": "string",
              "description": "Filters on what kind of movement it is."
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Returns only movements booked at or after this instant (ISO 8601 UTC datetime). Set it to the transactionDate of the last row you processed to read incrementally.",
            "schema": {
              "type": "string",
              "description": "Returns only movements booked at or after this instant (ISO 8601 UTC datetime). Set it to the transactionDate of the last row you processed to read incrementally.",
              "format": "date-time"
            }
          },
          {
            "name": "until",
            "in": "query",
            "description": "Returns only movements booked at or before this instant (ISO 8601 UTC datetime).",
            "schema": {
              "type": "string",
              "description": "Returns only movements booked at or before this instant (ISO 8601 UTC datetime).",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicInventoryTransactionResponse"
                }
              }
            }
          },
          "400": {
            "description": "?transactionType= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'inventory:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "inventory:read"
      }
    },
    "/preview/invoices/{invoiceNumber}": {
      "get": {
        "tags": [
          "Invoices"
        ],
        "summary": "Get an invoice by invoice number",
        "description": "Returns the invoice including its lines. Invoices are read-only over the public API — they are created from sales orders inside Fluit. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `invoices:read` scope.",
        "operationId": "Preview_GetInvoice",
        "parameters": [
          {
            "name": "invoiceNumber",
            "in": "path",
            "description": "Invoice number of the invoice to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Invoice number of the invoice to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicInvoiceResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No invoice with that invoice number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'invoices:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "invoices:read"
      }
    },
    "/preview/invoices": {
      "get": {
        "tags": [
          "Invoices"
        ],
        "summary": "List invoices",
        "description": "Returns a paginated list of sales invoices, newest invoice date first. Lines are omitted from the list — fetch a single invoice via its links.self for the full document. ?modifiedSince= returns both created and modified invoices, so it can be used for delta sync; deletions are reported by GET /preview/deletions. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `invoices:read` scope.",
        "operationId": "Preview_ListInvoices",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches the invoice number and the customer's own document number, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches the invoice number and the customer's own document number, case-insensitively and on partial words."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on where the invoice stands in its ledger lifecycle. Paid and PartiallyPaid are accepted here for backwards compatibility and are read as ?paymentStatus=.",
            "schema": {
              "enum": [
                "Open",
                "Booked",
                "Cancelled"
              ],
              "type": "string",
              "description": "Filters on where the invoice stands in its ledger lifecycle. Paid and PartiallyPaid are accepted here for backwards compatibility and are read as ?paymentStatus=."
            }
          },
          {
            "name": "paymentStatus",
            "in": "query",
            "description": "Filters on how much of the invoice has been paid.",
            "schema": {
              "enum": [
                "Unpaid",
                "PartiallyPaid",
                "Paid",
                "AwaitingTaxReduction"
              ],
              "type": "string",
              "description": "Filters on how much of the invoice has been paid."
            }
          },
          {
            "name": "customerNumber",
            "in": "query",
            "description": "Returns only the invoices issued to this customer number.",
            "schema": {
              "type": "string",
              "description": "Returns only the invoices issued to this customer number."
            }
          },
          {
            "name": "invoiceDateFrom",
            "in": "query",
            "description": "Returns only invoices dated on or after this date (ISO 8601 date).",
            "schema": {
              "type": "string",
              "description": "Returns only invoices dated on or after this date (ISO 8601 date).",
              "format": "date"
            }
          },
          {
            "name": "invoiceDateTo",
            "in": "query",
            "description": "Returns only invoices dated on or before this date (ISO 8601 date).",
            "schema": {
              "type": "string",
              "description": "Returns only invoices dated on or before this date (ISO 8601 date).",
              "format": "date"
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicInvoiceResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= or ?paymentStatus= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'invoices:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "invoices:read"
      }
    },
    "/preview/items/{itemNumber}/categories": {
      "post": {
        "tags": [
          "Items"
        ],
        "summary": "Add a category to an item",
        "description": "Files the item under one more category, keeping the categories it already has. The item's categories are listed under categories in GET /preview/items/{itemNumber}. Adding a category the item already has changes nothing and still returns 204, so a sync can re-run without special-casing. To move the item to another main category, use categoryCode on PATCH /preview/items/{itemNumber}: it replaces the main category and leaves every other category untouched. A category counts as main — isPrimary: true on the item — when its category type is the primary one or when it has no category type, so a category created without a type is a main category too. A category type that allows one category per item — the primary one does — rejects a second one here with ItemCategoryAssignments.SingleAssignmentViolation. Known error codes: categoryCode, ItemCategoryAssignments.DirectAssignmentNotAllowed, ItemCategoryAssignments.SingleAssignmentViolation, Item.NotFound.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_AddItemCategory",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to categorise.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to categorise."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddItemCategoryRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Add a category",
                  "value": {
                    "categoryCode": "WEB-SPEAKERS"
                  }
                },
                "full": {
                  "summary": "Add a category at a given position",
                  "value": {
                    "categoryCode": "WEB-SPEAKERS",
                    "sortOrder": 2
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "categoryCode is missing or is not an active category, the category does not take items directly (pick one of its subcategories), or its category type allows one category per item and the item already has one of that type.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/item-warehouses/batch": {
      "post": {
        "tags": [
          "Items"
        ],
        "summary": "Update warehouse settings on many items in one call",
        "description": "Updates up to 200 item-warehouse rows per call — for example reorder points recalculated outside Fluit once a month. Each row is a PATCH /preview/items/{itemNumber}/warehouses/{warehouseCode} body plus its address, `itemNumber` and `warehouseCode`, and is validated exactly like that PATCH. The batch only updates rows that exist; it does not set an item up in a new warehouse.\n\nThe HTTP status describes the request, not the rows: a well-formed batch always answers 200, and every row carries its own `outcome` (`updated` or `failed`) plus an `error` when it failed. A failed row changes nothing on that row and never blocks the others — re-send only the failed rows. Typical row errors: `ItemWarehouse.NotFound` (the item, the warehouse or the pairing does not exist), a validation error naming the field, and `ItemWarehouse.ConcurrentModification` when the row changed while it was written. 4xx is reserved for the batch itself.\n\nAn `Idempotency-Key` is required like on every POST under /preview; deriving it from the run and the batch index (for example `sha256(runId + ':' + batchIndex)`) makes an interrupted run safe to resume.\n\nOnly provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. isActive, lotSizing, replenishmentType and importance cannot be null. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. Rules are checked against the resulting combination, not field by field, so raising minQuantity and maxQuantity together in one call (10/20 → 30/40) is accepted. Decimals are sent as strings (\"12.5\"); numbers are accepted too. Enums are sent by name. Quantities are 0 to 99999999999999.9999 and lead times 0 to 365 days.\n\n**How MRP reads these settings.** `minQuantity` is the reorder point. When projected stock falls below max(safety stock, minQuantity), MRP proposes replenishment according to `lotSizing`: `LotForLot` fills to the safety stock and ignores the reorder point, `FixedReorderQuantity` orders `reorderQuantity` (required, > 0) in whole multiples, `FillToMax` orders up to `maxQuantity` (required). The safety stock is `safetyStock`, else `calculatedSafetyStock`, else zero. A purchase quantity is then rounded up to the supplier's `minOrderQuantity` and `orderMultiple`.\n\n**Which lead time MRP uses for a purchased item**, first one set wins: (1) the lead time on an active purchase agreement line, (2) `leadTimeDays` on the supplier item of the supplier MRP picks (agreement supplier, else the primary supplier) — see GET/PATCH /preview/suppliers/{supplierNumber}/items, (3) `leadTimeDays` on this item-warehouse row, (4) 14 days, with a warning in the MRP run. A manufactured item uses (3) then (4). A transferred item uses `transferLeadTimeDays`, else the warehouse's transport time.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_BatchPatchItemWarehouses",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchPatchItemWarehousesRequest"
              },
              "examples": {
                "reorder-points": {
                  "summary": "Monthly reorder point update",
                  "value": {
                    "itemWarehouses": [
                      {
                        "itemNumber": "670-00001",
                        "warehouseCode": "MAIN",
                        "minQuantity": "40",
                        "maxQuantity": "120"
                      },
                      {
                        "itemNumber": "670-00002",
                        "warehouseCode": "MAIN",
                        "minQuantity": "15",
                        "safetyStock": "5"
                      }
                    ]
                  }
                },
                "policy": {
                  "summary": "Switch to fixed reorder quantity",
                  "value": {
                    "itemWarehouses": [
                      {
                        "itemNumber": "670-00001",
                        "warehouseCode": "MAIN",
                        "lotSizing": "FixedReorderQuantity",
                        "reorderQuantity": "50",
                        "leadTimeDays": 10
                      },
                      {
                        "itemNumber": "670-00003",
                        "warehouseCode": "MAIN",
                        "safetyStock": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchPatchItemWarehousesResponse"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, has no itemWarehouses array, the array is empty (ItemWarehouses.Batch.Empty) or holds more than 200 rows (ItemWarehouses.Batch.TooManyRows).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/items/batch": {
      "post": {
        "tags": [
          "Items"
        ],
        "summary": "Create or update many items in one call",
        "description": "Loads up to 200 items per call. `itemNumber` is required on every row — unlike POST /preview/items, this endpoint never generates one.\n\nThe HTTP status describes the request, not the rows: a well-formed batch always answers 200, and every row carries its own `outcome` (`created`, `updated` or `failed`) plus an `error` when it failed. A single bad row therefore never blocks the rest of the batch — re-send only the failed rows. 4xx is reserved for the batch itself: more than 200 rows, a missing scope, malformed JSON.\n\n`categoryCode`, `brandCode` and `unitCode` place the item in the catalogue. They are looked up once per batch and must already exist — the batch never creates a category, brand or unit, since a typo would otherwise silently become a new one. A row naming an unknown code fails on its own (`Items.Bulk.UnknownCategoryCode`, `Items.Bulk.UnknownBrandCode`, `Items.Bulk.UnknownUnitCode`) and leaves the rest of the batch alone. Load the catalogue first with POST /preview/categories and POST /preview/brands; GET /preview/reference/units lists the unit codes.\n\n**Variants.** A `VariantMaster` row names its axes in `variantAxes`; a variant row names its master in `parentItemNumber` and its place in the matrix in `variantValues`. Put masters before their variants — rows run in order, so a master created earlier in the same batch is found. Each row is one transaction: a variant that cannot be placed (`Variant.IncompleteCombination`, `Variant.DuplicateVariant`, a master that is not a `VariantMaster`) is not created at all. Variant attributes are looked up by name and must exist (`Items.Bulk.UnknownVariantAttribute`); their values are created as needed.\n\n`mode` is `upsert` (default), `create` or `update`. An `Idempotency-Key` is required like on every POST under /preview; deriving it from the run and the batch index (for example `sha256(runId + ':' + batchIndex)`) makes an interrupted load safe to resume without duplicates.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_BatchUpsertItems",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchUpsertItemsRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Two rows, upsert",
                  "value": {
                    "items": [
                      {
                        "itemNumber": "670-00001",
                        "name": "HDMI cable 2 m",
                        "salesPrice": "249.00"
                      },
                      {
                        "itemNumber": "670-00002",
                        "name": "HDMI cable 5 m",
                        "salesPrice": "319.00"
                      }
                    ]
                  }
                },
                "catalogue": {
                  "summary": "Rows filed under a category and a brand",
                  "value": {
                    "items": [
                      {
                        "itemNumber": "670-00001",
                        "name": "HDMI cable 2 m",
                        "salesPrice": "249.00",
                        "categoryCode": "HDMI",
                        "brandCode": "KORDZ",
                        "unitCode": "ST",
                        "width": "12.00",
                        "height": "3.50",
                        "depth": "12.00"
                      }
                    ]
                  }
                },
                "variants": {
                  "summary": "A master and two variants",
                  "value": {
                    "items": [
                      {
                        "itemNumber": "655-001",
                        "name": "Verona chair",
                        "itemType": "VariantMaster",
                        "variantAxes": [
                          "Material",
                          "Finish"
                        ]
                      },
                      {
                        "itemNumber": "655-001-OAK",
                        "name": "Verona chair, oak oiled",
                        "parentItemNumber": "655-001",
                        "variantValues": {
                          "Material": "Solid oak",
                          "Finish": "Oak oiled"
                        }
                      },
                      {
                        "itemNumber": "655-001-ASH",
                        "name": "Verona chair, ash blond",
                        "parentItemNumber": "655-001",
                        "status": "PhasingOut",
                        "variantValues": {
                          "Material": "Solid ash",
                          "Finish": "Ash blond"
                        }
                      }
                    ]
                  }
                },
                "update-only": {
                  "summary": "Update prices on existing items",
                  "value": {
                    "mode": "update",
                    "items": [
                      {
                        "itemNumber": "670-00001",
                        "salesPrice": "259.00"
                      },
                      {
                        "itemNumber": "670-00002",
                        "salesPrice": "329.00"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchUpsertItemsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/items": {
      "post": {
        "tags": [
          "Items"
        ],
        "summary": "Create an item",
        "description": "Creates a new item for the authenticated tenant. Item number is auto-generated if not provided. The response body is the same representation as GET /preview/items/{itemNumber}; the canonical URL is returned in the Location header and in links.self.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_CreateItem",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateItemRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal — name only",
                  "value": {
                    "name": "Widget Pro 3000"
                  }
                },
                "full": {
                  "summary": "Full item with pricing and customs",
                  "value": {
                    "name": "Widget Pro 3000",
                    "itemNumber": "WIDGET-PRO",
                    "description": "High-quality widget for professional use.",
                    "barcode": "7350100500001",
                    "salesPrice": "299.00",
                    "costPrice": "120.00",
                    "hsCode": "84795000",
                    "countryOfOrigin": "SE"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, for example an item number containing characters outside A-Z, 0-9, hyphen and underscore.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      },
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "List items",
        "description": "Returns a paginated list of items for the authenticated tenant. Sorted by item number. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200. Filters combine with AND. Enum filters are matched case-insensitively and an unknown value returns 400. Delta sync: ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Newly created items are included even though they have no modifiedDate yet. Deletions are not visible here: a deleted record is really gone, so it simply stops appearing, which is indistinguishable from \"unchanged\". Poll GET /preview/deletions?deletedSince= alongside this endpoint to learn what was removed. \n\nRequires the `items:read` scope.",
        "operationId": "Preview_ListItems",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches item number, name and description, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches item number, name and description, case-insensitively and on partial words."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on the item's lifecycle status.",
            "schema": {
              "enum": [
                "Draft",
                "PendingApproval",
                "Active",
                "PhasingOut",
                "Discontinued",
                "Archived"
              ],
              "type": "string",
              "description": "Filters on the item's lifecycle status."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "reference",
            "in": "query",
            "description": "Looks the value up as an identifier: first the item number, then the item's own barcode, then barcodes on alternative units (case, pallet) and finally cross-references such as manufacturer (MPN) and OEM numbers. The identifier that matched is reported per row in matchedOn. Barcodes are not guaranteed unique, so this returns a list rather than one item.",
            "schema": {
              "type": "string",
              "description": "Looks the value up as an identifier: first the item number, then the item's own barcode, then barcodes on alternative units (case, pallet) and finally cross-references such as manufacturer (MPN) and OEM numbers. The identifier that matched is reported per row in matchedOn. Barcodes are not guaranteed unique, so this returns a list rather than one item."
            }
          },
          {
            "name": "referenceType",
            "in": "query",
            "description": "Restricts ?reference= to one cross-reference type instead of searching every identifier.",
            "schema": {
              "enum": [
                "Manufacturer",
                "Oem",
                "IndustryStandard",
                "Superseded",
                "Competitor",
                "Barcode",
                "Custom"
              ],
              "type": "string",
              "description": "Restricts ?reference= to one cross-reference type instead of searching every identifier."
            }
          },
          {
            "name": "itemNumbers",
            "in": "query",
            "description": "Comma-separated item numbers to fetch in one call, so a change notification covering many items costs one request instead of one each. Max 200 values.",
            "schema": {
              "type": "string",
              "description": "Comma-separated item numbers to fetch in one call, so a change notification covering many items costs one request instead of one each. Max 200 values."
            }
          },
          {
            "name": "itemType",
            "in": "query",
            "description": "Filters on what kind of item it is.",
            "schema": {
              "enum": [
                "StockItem",
                "NonStockItem",
                "Service",
                "Work",
                "Consumable",
                "Kit",
                "Phantom",
                "Charge",
                "VariantMaster"
              ],
              "type": "string",
              "description": "Filters on what kind of item it is."
            }
          },
          {
            "name": "grade",
            "in": "query",
            "description": "Filters on the item's quality grade.",
            "schema": {
              "enum": [
                "A",
                "B",
                "C",
                "D"
              ],
              "type": "string",
              "description": "Filters on the item's quality grade."
            }
          },
          {
            "name": "publishOnWeb",
            "in": "query",
            "description": "Retired. Use sales-channel publications instead.",
            "schema": {
              "type": "boolean",
              "description": "Retired. Use sales-channel publications instead."
            }
          },
          {
            "name": "isSellable",
            "in": "query",
            "description": "Filters on whether the item may be sold.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the item may be sold."
            }
          },
          {
            "name": "isConfigurable",
            "in": "query",
            "description": "True returns only made-to-order items that have a configuration schema at GET /preview/items/{itemNumber}/configuration; false returns only the plain catalogue items.",
            "schema": {
              "type": "boolean",
              "description": "True returns only made-to-order items that have a configuration schema at GET /preview/items/{itemNumber}/configuration; false returns only the plain catalogue items."
            }
          },
          {
            "name": "isVariant",
            "in": "query",
            "description": "True returns only variants, false only non-variants.",
            "schema": {
              "type": "boolean",
              "description": "True returns only variants, false only non-variants."
            }
          },
          {
            "name": "categoryCode",
            "in": "query",
            "description": "Filters on the stable category code, counting only active and non-deleted assignments. Subcategories are not included — expand the tree client-side. This is also how you build the picker for an ItemSelection feature, by passing its selectableItemCategoryCode.",
            "schema": {
              "type": "string",
              "description": "Filters on the stable category code, counting only active and non-deleted assignments. Subcategories are not included — expand the tree client-side. This is also how you build the picker for an ItemSelection feature, by passing its selectableItemCategoryCode."
            }
          },
          {
            "name": "brandCode",
            "in": "query",
            "description": "Filters on the brand code.",
            "schema": {
              "type": "string",
              "description": "Filters on the brand code."
            }
          },
          {
            "name": "parentItemNumber",
            "in": "query",
            "description": "Returns the variants of one variant master, given by its item number.",
            "schema": {
              "type": "string",
              "description": "Returns the variants of one variant master, given by its item number."
            }
          },
          {
            "name": "attribute",
            "in": "query",
            "description": "Filters on an attribute code from GET /preview/attributes. Alone it returns the items that have the attribute filled in at all — useful for finding what is still missing. Combine with attributeValue to filter on the value.",
            "schema": {
              "type": "string",
              "description": "Filters on an attribute code from GET /preview/attributes. Alone it returns the items that have the attribute filled in at all — useful for finding what is still missing. Combine with attributeValue to filter on the value."
            }
          },
          {
            "name": "attributeValue",
            "in": "query",
            "description": "The attribute value to match, exactly. Requires ?attribute=. Numbers are compared as numbers, so 40 matches a stored 40.000000. For partial matches across all text, use ?search= instead.",
            "schema": {
              "type": "string",
              "description": "The attribute value to match, exactly. Requires ?attribute=. Numbers are compared as numbers, so 40 matches a stored 40.000000. For partial matches across all text, use ?search= instead."
            }
          },
          {
            "name": "language",
            "in": "query",
            "description": "ISO 639-1 language code, e.g. en. Returns name, description and short description translated to that language where a translation exists; other fields and untranslated texts come back in the base language. An unknown or inactive language is ignored.",
            "schema": {
              "type": "string",
              "description": "ISO 639-1 language code, e.g. en. Returns name, description and short description translated to that language where a translation exists; other fields and untranslated texts come back in the base language. An unknown or inactive language is ignored."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicItemResponse"
                }
              }
            }
          },
          "400": {
            "description": "An enum filter (status, referenceType, itemType, grade) got a value outside its list, itemNumbers held more than 200 values, or the retired publishOnWeb filter was provided.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/items/{itemNumber}/assets/{assetId}": {
      "delete": {
        "tags": [
          "Items"
        ],
        "summary": "Delete an item image or document",
        "description": "Removes an image, datasheet (PDF) or CAD drawing (DWG) from the item. Deleting is how you replace a file: the upload endpoint always appends, so a new file lands after the one it was meant to replace. To change a file's category, name or order without replacing it — and without changing its url — use PATCH on the same address instead. Only files this surface manages can be deleted — public, current ones of a type the upload endpoint accepts. An id that belongs to an internal document, a superseded revision, a file type that cannot be uploaded here or another item answers 404, the same as an id that does not exist: what cannot be uploaded here cannot be deleted here. Nothing checks whether anything still points at the url — a storefront or feed that cached it keeps a broken link until it refreshes. Deleting the item's primary image leaves the item without one, and nothing promotes a replacement: thumbnailUrl in GET /preview/items goes null until another image is marked primary. Upload the replacement and mark it primary before deleting if the item should never be without a picture. The deletion leaves a tombstone under GET /preview/deletions with resource 'item-assets' and the business key {itemNumber}/{assetId}, so a client syncing with ?modifiedSince= sees the file disappear. Known error codes: Item.NotFound, ItemAsset.NotFound.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_DeleteItemAsset",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item the file belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item the file belongs to."
            }
          },
          {
            "name": "assetId",
            "in": "path",
            "description": "The file's id, from GET /preview/items/{itemNumber}/assets.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The file's id, from GET /preview/items/{itemNumber}/assets.",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, or no file with that id on the item.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      },
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "Read one item asset",
        "description": "Returns the record for one image or document on the item: its url plus the metadata the listing carries. This endpoint returns JSON, not the file itself — the bytes are fetched from GET /preview/items/{itemNumber}/assets/{assetId}/download, which needs the same API key. This is the address the upload's Location header points at. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_GetItemAsset",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item the asset belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item the asset belongs to."
            }
          },
          {
            "name": "assetId",
            "in": "path",
            "description": "The asset's id, as returned by the upload and by the listing.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The asset's id, as returned by the upload and by the listing.",
              "format": "uuid"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemAssetResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, or no asset with that id on the item.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      },
      "patch": {
        "tags": [
          "Items"
        ],
        "summary": "Update an item file's metadata",
        "description": "Partially updates an image's or document's metadata without uploading it again, so its url stays the same and links to it keep working. Only provided fields are updated (JSON Merge Patch semantics). Pass null to clear displayName, altText, description or languageCode; category, sortOrder and isPrimary cannot be null. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. category takes an image role for an image and a document category code for a document — the same values as the upload endpoint. isPrimary=true makes the image the item's primary image and the previous one loses the flag. The file itself cannot be replaced here: a new file is a new upload, with a new url. The same files are reachable here as through GET /preview/items/{itemNumber}/assets — public, current images, PDFs and DWGs. Anything else answers 404, the same as an id that does not exist. Known error codes: Item.NotFound, ItemAsset.NotFound, ItemAsset.CategoryDoesNotMatchType, ItemAsset.NotImage, DocumentCategory.CodeNotFound.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_PatchItemAsset",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item the file belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item the file belongs to."
            }
          },
          {
            "name": "assetId",
            "in": "path",
            "description": "The file's id, from GET /preview/items/{itemNumber}/assets.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The file's id, from GET /preview/items/{itemNumber}/assets.",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchItemAssetRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchItemAssetRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, or a field present in it failed validation: category was null, did not fit the file (an image role on a document or the other way round) or is not an active document category; isPrimary was false or set on a document; sortOrder was negative; or a text field was longer than allowed.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, or no file with that id on the item.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/items/{itemNumber}/assets/{assetId}/download": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "Download an item asset",
        "description": "Streams the asset file (image or document). Externally hosted assets return a 302 redirect to the external URL. Only assets marked as public can be downloaded.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_DownloadItemAsset",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item the asset belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item the asset belongs to."
            }
          },
          {
            "name": "assetId",
            "in": "path",
            "description": "Id of the asset, as returned by the asset list endpoint.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Id of the asset, as returned by the asset list endpoint.",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "302": {
            "description": "Found",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No public asset with that id on that item — the same answer whether the item, the asset or only its public flag is missing.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/items/{itemNumber}/availability": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "Get item stock availability",
        "description": "Returns the item's stock availability summed across all active warehouses and broken down per warehouse. availableQuantity is the quantity that can be promised to new orders (on hand minus reservations). Items never stocked in a warehouse return an empty warehouses list with zero totals. The warehouse breakdown is bounded by the tenant's warehouse count and is not paginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_GetItemAvailability",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to read availability for.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to read availability for."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemAvailabilityResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/items/{itemNumber}": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "Get an item by item number",
        "description": "Returns the full details of an item by its unique item number: all orderable units with barcodes and conversion factors (base unit first), specification attributes, category assignments, cross-references (MPN/OEM/extra barcodes) and, for variants, the parent item and variant attribute values. The list endpoint returns a leaner representation without these collections. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged. The validator follows the whole record, so a change to a nested part invalidates it too.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_GetItem",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to read."
            }
          },
          {
            "name": "language",
            "in": "query",
            "description": "ISO 639-1 language code, e.g. en. Returns name, description and short description translated to that language where a translation exists; other fields and untranslated texts come back in the base language. An unknown or inactive language is ignored.",
            "schema": {
              "type": "string",
              "description": "ISO 639-1 language code, e.g. en. Returns name, description and short description translated to that language where a translation exists; other fields and untranslated texts come back in the base language. An unknown or inactive language is ignored."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemDetailResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      },
      "patch": {
        "tags": [
          "Items"
        ],
        "summary": "Update an item",
        "description": "Partially updates an item. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. itemNumber cannot be changed here — it is the resource's public key and the address external systems reference.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_PatchItem",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to update.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to update."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchItemRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchItemRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, or a field present in it failed validation.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/items/{itemNumber}/price": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "Calculate item price",
        "description": "Calculates the price for an item via the price engine — the same price an order line would get. quantityBreaks lists the volume price tiers of the applied price list. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_GetItemPrice",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to price.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to price."
            }
          },
          {
            "name": "customerNumber",
            "in": "query",
            "description": "Prices for this customer, applying their price lists, agreements and campaigns. Omit for the default price.",
            "schema": {
              "type": "string",
              "description": "Prices for this customer, applying their price lists, agreements and campaigns. Omit for the default price."
            }
          },
          {
            "name": "currencyCode",
            "in": "query",
            "description": "ISO 4217 currency to price in. Defaults to the customer's currency, then the tenant base currency.",
            "schema": {
              "type": "string",
              "description": "ISO 4217 currency to price in. Defaults to the customer's currency, then the tenant base currency."
            }
          },
          {
            "name": "quantity",
            "in": "query",
            "description": "Quantity to price, which is what activates volume pricing. Must be greater than zero. Default 1.",
            "schema": {
              "type": "number",
              "description": "Quantity to price, which is what activates volume pricing. Must be greater than zero. Default 1.",
              "format": "double",
              "default": 1
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemPriceResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The quantity is zero or less, or no customer has that customer number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/items/{itemNumber}/warehouses/{warehouseCode}": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "Get an item's warehouse settings",
        "description": "Returns the reorder point, stock levels, safety stock, lead time, lot sizing, supply policy and replenishment settings for one item in one warehouse. Stock on hand is read from GET /preview/items/{itemNumber}/availability. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\n**How MRP reads these settings.** `minQuantity` is the reorder point. When projected stock falls below max(safety stock, minQuantity), MRP proposes replenishment according to `lotSizing`: `LotForLot` fills to the safety stock and ignores the reorder point, `FixedReorderQuantity` orders `reorderQuantity` (required, > 0) in whole multiples, `FillToMax` orders up to `maxQuantity` (required). The safety stock is `safetyStock`, else `calculatedSafetyStock`, else zero. A purchase quantity is then rounded up to the supplier's `minOrderQuantity` and `orderMultiple`.\n\n**Which lead time MRP uses for a purchased item**, first one set wins: (1) the lead time on an active purchase agreement line, (2) `leadTimeDays` on the supplier item of the supplier MRP picks (agreement supplier, else the primary supplier) — see GET/PATCH /preview/suppliers/{supplierNumber}/items, (3) `leadTimeDays` on this item-warehouse row, (4) 14 days, with a warning in the MRP run. A manufactured item uses (3) then (4). A transferred item uses `transferLeadTimeDays`, else the warehouse's transport time.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_GetItemWarehouse",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item."
            }
          },
          {
            "name": "warehouseCode",
            "in": "path",
            "description": "Code of the warehouse.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the warehouse."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemWarehouseResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, no warehouse with that code, or the item is not set up in that warehouse. The three are separate errors and the problem detail says which.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      },
      "patch": {
        "tags": [
          "Items"
        ],
        "summary": "Update an item's warehouse settings",
        "description": "Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. isActive, lotSizing, replenishmentType and importance cannot be null. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. Rules are checked against the resulting combination, not field by field, so raising minQuantity and maxQuantity together in one call (10/20 → 30/40) is accepted. Decimals are sent as strings (\"12.5\"); numbers are accepted too. Enums are sent by name. Quantities are 0 to 99999999999999.9999 and lead times 0 to 365 days.\n\n**How MRP reads these settings.** `minQuantity` is the reorder point. When projected stock falls below max(safety stock, minQuantity), MRP proposes replenishment according to `lotSizing`: `LotForLot` fills to the safety stock and ignores the reorder point, `FixedReorderQuantity` orders `reorderQuantity` (required, > 0) in whole multiples, `FillToMax` orders up to `maxQuantity` (required). The safety stock is `safetyStock`, else `calculatedSafetyStock`, else zero. A purchase quantity is then rounded up to the supplier's `minOrderQuantity` and `orderMultiple`.\n\n**Which lead time MRP uses for a purchased item**, first one set wins: (1) the lead time on an active purchase agreement line, (2) `leadTimeDays` on the supplier item of the supplier MRP picks (agreement supplier, else the primary supplier) — see GET/PATCH /preview/suppliers/{supplierNumber}/items, (3) `leadTimeDays` on this item-warehouse row, (4) 14 days, with a warning in the MRP run. A manufactured item uses (3) then (4). A transferred item uses `transferLeadTimeDays`, else the warehouse's transport time.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_PatchItemWarehouse",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item."
            }
          },
          {
            "name": "warehouseCode",
            "in": "path",
            "description": "Code of the warehouse.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the warehouse."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchItemWarehouseRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchItemWarehouseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a field failed validation, transferFromWarehouseCode names a warehouse that does not exist, one of isActive, lotSizing, replenishmentType and importance was sent as null, or the resulting combination breaks a rule: ItemWarehouses.MinQuantityExceedsMaxQuantity, ItemWarehouses.InvalidQuantityValue, ItemWarehouses.LotSizingRequiresReorderQuantity, ItemWarehouses.LotSizingRequiresMaxQuantity, ItemWarehouses.InvalidServiceLevel, or a transfer source that is this warehouse, is unusable or closes a cycle (Warehouses.TransferSource*, Warehouses.TransferChainTooLong).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, no warehouse with that code, or the item is not set up in that warehouse.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The row was changed by someone else, typically a stock movement, while it was being written. Send the request again.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/attributes": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "List attribute definitions",
        "description": "Returns the active product attribute definitions — the specification fields an item can carry — with the rules that govern their values: data type, unit, allowed values for a fixed list, numeric bounds, a pattern text must match, and whether an item may hold several values. Use code when setting a value with PUT /preview/items/{itemNumber}/attributes/{attributeCode}, and when filtering GET /preview/items with ?attribute=. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_ListAttributes",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches the attribute code and name, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches the attribute code and name, case-insensitively and on partial words."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicAttributeResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/inventory/availability": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "List stock availability for many items",
        "description": "Returns stock availability for every stocked item, paginated, with the same per-warehouse breakdown as GET /preview/items/{itemNumber}/availability — including whether movements in that warehouse require serial or batch numbers. Use this instead of calling the per-item endpoint in a loop: a catalogue of a few thousand SKUs otherwise consumes the entire rate limit budget on every sync cycle. Items with no stock record in any active warehouse are omitted. Pagination is over items, never over warehouse rows, so an item's totals are always complete. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_ListAvailability",
        "parameters": [
          {
            "name": "itemNumbers",
            "in": "query",
            "description": "Comma-separated item numbers to limit the result to. Max 200 values.",
            "schema": {
              "type": "string",
              "description": "Comma-separated item numbers to limit the result to. Max 200 values."
            }
          },
          {
            "name": "warehouseCode",
            "in": "query",
            "description": "Restricts the breakdown to one warehouse, in which case the totals cover that warehouse only.",
            "schema": {
              "type": "string",
              "description": "Restricts the breakdown to one warehouse, in which case the totals cover that warehouse only."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only items whose stock records were created or changed at or after this instant (ISO 8601 UTC datetime). This is what makes a recurring poll cheap.",
            "schema": {
              "type": "string",
              "description": "Returns only items whose stock records were created or changed at or after this instant (ISO 8601 UTC datetime). This is what makes a recurring poll cheap.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicItemAvailabilityResponse"
                }
              }
            }
          },
          "400": {
            "description": "itemNumbers held more than 200 values.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/items/{itemNumber}/assets": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "List item assets",
        "description": "Returns a paginated list of the item's public images and documents, primary image first and then by sort order. Only assets marked as public are included. url points either to an external location or to GET /preview/items/{itemNumber}/assets/{assetId}/download (same API key required). Use languageCode to pick language-specific assets where present. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_ListItemAssets",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item whose assets to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item whose assets to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicItemAssetResponse"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      },
      "post": {
        "tags": [
          "Items"
        ],
        "summary": "Upload an item image or document",
        "description": "Uploads a product image, a datasheet (PDF) or a CAD drawing (DWG) as multipart/form-data. The field name is 'file'; everything else is a query parameter. Supported types: PNG, JPEG, GIF and WebP up to 50 MB; PDF and DWG up to 100 MB. The file's own bytes decide what it is — a file that only claims to be an image or a PDF is rejected, and a DWG served as application/octet-stream is still recognised. The stored content type is the detected one. Uploaded files are always public: they are what the storefront and this API's list endpoint show. isPrimary=true makes an image the item's primary image, which is what the item's thumbnailUrl points at and what a storefront shows in listings; the item's previous primary image loses the flag. The response is the representation GET /preview/items/{itemNumber}/assets/{assetId} returns, and Location points at that address. This POST takes no Idempotency-Key — a multipart body cannot be hashed the way a JSON one can — so a retry after a network failure may create a second image. List the item's assets to see whether the first attempt landed before retrying, and remove a duplicate with DELETE /preview/items/{itemNumber}/assets/{assetId}. Uploads always append: a new image is sorted after the ones already on the item, so replacing a picture means uploading the new one and deleting the old. Known error codes: ItemAssets.EmptyFile, ItemAssets.FileTooLarge, ItemAssets.UnsupportedType, ItemAssets.NotAnImage, ItemAssets.ContentMismatch, Item.NotFound.\n\n**Not idempotent.** A file upload carries no Idempotency-Key: the body cannot be buffered and hashed the way a JSON request can. Retrying after a network failure may therefore create a second copy — list the folder and compare before retrying, or delete the duplicate afterwards.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_UploadItemAsset",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to attach the file to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to attach the file to."
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Category. An image takes an image category (MainImage, GalleryImage, LifestyleImage, TechnicalImage, VariantImage) and defaults to MainImage when isPrimary is true, otherwise GalleryImage. A document takes the code of one of the tenant's active document categories and defaults to CadDrawing for a DWG and Datasheet for a PDF, or the tenant's default category when it has neither.",
            "schema": {
              "type": "string",
              "description": "Category. An image takes an image category (MainImage, GalleryImage, LifestyleImage, TechnicalImage, VariantImage) and defaults to MainImage when isPrimary is true, otherwise GalleryImage. A document takes the code of one of the tenant's active document categories and defaults to CadDrawing for a DWG and Datasheet for a PDF, or the tenant's default category when it has neither."
            }
          },
          {
            "name": "isPrimary",
            "in": "query",
            "description": "Whether this becomes the item's primary image. Defaults to false. Images only.",
            "schema": {
              "type": "boolean",
              "description": "Whether this becomes the item's primary image. Defaults to false. Images only."
            }
          },
          {
            "name": "displayName",
            "in": "query",
            "description": "Display name in listings. Defaults to the file name.",
            "schema": {
              "type": "string",
              "description": "Display name in listings. Defaults to the file name."
            }
          },
          {
            "name": "altText",
            "in": "query",
            "description": "Alt text for accessibility and SEO. Strongly recommended.",
            "schema": {
              "type": "string",
              "description": "Alt text for accessibility and SEO. Strongly recommended."
            }
          },
          {
            "name": "description",
            "in": "query",
            "description": "Free-text description.",
            "schema": {
              "type": "string",
              "description": "Free-text description."
            }
          },
          {
            "name": "languageCode",
            "in": "query",
            "description": "ISO 639-1 code when the image is language-specific, e.g. sv. Omit for a language-neutral image.",
            "schema": {
              "type": "string",
              "description": "ISO 639-1 code when the image is language-specific, e.g. sv. Omit for a language-neutral image."
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemAssetResponse"
                }
              }
            }
          },
          "400": {
            "description": "The file is empty, larger than its type allows, not one of the supported types, does not match its declared type, has no file name, category does not fit the file (an image category on a document or the other way round), isPrimary is set on a document, or displayName, altText, description or languageCode is longer than allowed.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "The request body is larger than 100 MB plus multipart overhead.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/items/{itemNumber}/relations": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "List item relations",
        "description": "Returns the item's relations to other items — accessories, spare parts, related products, cross- and up-sells, replacements and graded alternatives. Besides the relations set up on this item (direction Outgoing), the list includes relations set up on another item and marked bidirectional (direction Incoming), since those are shown on this item's product page too. Sorted with outgoing relations first, then by relation type, sort order and item number. Add relations with POST /preview/item-relations/batch. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_ListItemRelations",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item whose relations to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item whose relations to list."
            }
          },
          {
            "name": "relationType",
            "in": "query",
            "description": "Only relations of this type.",
            "schema": {
              "enum": [
                "Related",
                "Accessory",
                "CrossSell",
                "UpSell",
                "SparePart",
                "GradedAlternative",
                "Replacement"
              ],
              "type": "string",
              "description": "Only relations of this type."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicItemRelationResponse"
                }
              }
            }
          },
          "400": {
            "description": "relationType is not one of the relation types.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/items/{itemNumber}/variants": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "List an item's variants",
        "description": "Returns the variants belonging to a variant master, e.g. every colour and size of a T-shirt. The master itself declares which axes it varies on — read variantAxes on GET /preview/items/{itemNumber} — and each variant here reports its own values in variantAttributes. Returns 404 only if the item number does not exist; an item that is not a variant master returns an empty page, so a catalogue sync can call this for every item without knowing in advance which ones have variants. The status filter is matched case-insensitively and an unknown value returns 400. Sorted by item number. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_ListItemVariants",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the variant master whose variants to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the variant master whose variants to list."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on the variant's lifecycle status.",
            "schema": {
              "enum": [
                "Draft",
                "PendingApproval",
                "Active",
                "PhasingOut",
                "Discontinued",
                "Archived"
              ],
              "type": "string",
              "description": "Filters on the variant's lifecycle status."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicItemVariantResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number. An item that exists but is not a variant master returns an empty page instead.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/item-warehouses": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "List item warehouse settings",
        "description": "Returns one row per item and warehouse the item is set up in, with the reorder point, stock levels, safety stock, lead time, lot sizing, supply policy and replenishment settings. Filter with itemNumber for one item's warehouses, or with warehouseCode for everything in one warehouse — the starting point for a periodic recalculation that writes back through POST /preview/item-warehouses/batch. Sorted by itemNumber, then warehouseCode. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\n**How MRP reads these settings.** `minQuantity` is the reorder point. When projected stock falls below max(safety stock, minQuantity), MRP proposes replenishment according to `lotSizing`: `LotForLot` fills to the safety stock and ignores the reorder point, `FixedReorderQuantity` orders `reorderQuantity` (required, > 0) in whole multiples, `FillToMax` orders up to `maxQuantity` (required). The safety stock is `safetyStock`, else `calculatedSafetyStock`, else zero. A purchase quantity is then rounded up to the supplier's `minOrderQuantity` and `orderMultiple`.\n\n**Which lead time MRP uses for a purchased item**, first one set wins: (1) the lead time on an active purchase agreement line, (2) `leadTimeDays` on the supplier item of the supplier MRP picks (agreement supplier, else the primary supplier) — see GET/PATCH /preview/suppliers/{supplierNumber}/items, (3) `leadTimeDays` on this item-warehouse row, (4) 14 days, with a warning in the MRP run. A manufactured item uses (3) then (4). A transferred item uses `transferLeadTimeDays`, else the warehouse's transport time.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_ListItemWarehouses",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "query",
            "description": "Only rows for this item, matched exactly.",
            "schema": {
              "type": "string",
              "description": "Only rows for this item, matched exactly."
            }
          },
          {
            "name": "warehouseCode",
            "in": "query",
            "description": "Only rows in this warehouse, matched exactly.",
            "schema": {
              "type": "string",
              "description": "Only rows in this warehouse, matched exactly."
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filters on whether the item is active in the warehouse.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the item is active in the warehouse."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicItemWarehouseResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/items/{itemNumber}/features/{code}": {
      "put": {
        "tags": [
          "Items"
        ],
        "summary": "Set a selectable configuration choice on an item",
        "description": "Creates or replaces a Selection feature — a choice the buyer makes when ordering the item, such as the seat or back of a chair. The request carries the complete list of options: options are matched on `code`, so an unchanged option keeps its identity, new ones are added and options left out are removed. Sending the same request twice gives the same result, which makes the call safe in a migration that is re-run.\n\nAn option's `itemNumber` names the item it stands for; that item must exist and is pulled into the bill of materials when the option is chosen.\n\n`priceFormula` decides what the choice adds to the price. To charge for the item behind the chosen option — a chair sold as a frame, priced with its seat — send `SEAT_PRIS` for the feature `SEAT`. Every linked item then needs a sales price, or the configuration cannot be priced. Other feature types (measurements, formulas) are set up in the app.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_PutItemFeature",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item the choice is made on.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item the choice is made on."
            }
          },
          {
            "name": "code",
            "in": "path",
            "description": "Feature code, unique per item, e.g. SEAT.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Feature code, unique per item, e.g. SEAT."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutItemFeatureRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PutItemFeatureResponse"
                }
              }
            }
          },
          "400": {
            "description": "No options, more than one default, two options with the same code, an option naming an item that does not exist, a price formula that cannot be parsed, or an existing feature with this code that is not a selection.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/items/{itemNumber}/categories/{categoryCode}": {
      "delete": {
        "tags": [
          "Items"
        ],
        "summary": "Remove a category from an item",
        "description": "Takes the item out of one category and leaves its other categories as they are. Removing a category the item is not in is not an error — the end state is the same either way, so a retried call cannot fail on the second attempt. The 404 is about the item or a category code that does not exist at all, not about the link between them. Removing the item's main category leaves it without one, exactly like PATCH /preview/items/{itemNumber} with categoryCode set to null. Known error codes: Item.NotFound, Category.NotFound.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_RemoveItemCategory",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to take out of the category.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to take out of the category."
            }
          },
          {
            "name": "categoryCode",
            "in": "path",
            "description": "Code of the category to remove, as listed under categories on the item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the category to remove, as listed under categories on the item."
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, or no category with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/items/{itemNumber}/attributes/{attributeCode}": {
      "put": {
        "tags": [
          "Items"
        ],
        "summary": "Set an item attribute value",
        "description": "Sets one attribute value on an item, replacing any previous value. Pass value for a single-value attribute and values for one where isMultiValue is true — the list replaces the whole set, so values left out are removed. The value is checked against the attribute's rules: data type, numeric bounds, pattern, and its list of permitted values where it has one. See GET /preview/attributes for those rules. Send an empty value to clear the attribute.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_SetItemAttribute",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to set the value on.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to set the value on."
            }
          },
          {
            "name": "attributeCode",
            "in": "path",
            "description": "Attribute code, from GET /preview/attributes.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Attribute code, from GET /preview/attributes."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetItemAttributeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The value is not valid for the attribute — wrong type, outside its bounds, not in its list of permitted values, or not matching its pattern. Several values were given for an attribute that holds one.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, or no active attribute with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/items/{itemNumber}/translations": {
      "get": {
        "tags": [
          "Items"
        ],
        "summary": "List an item's translations",
        "description": "Returns the item's own texts (base) and, for every active language, the translated name, description, short description and search-engine title and description. A field without a translation is null, and missing lists the fields the item has a text for but the language lacks, so an integration can see which translations remain. Languages without any translation are included. To read an item with its texts already translated, use GET /preview/items/{itemNumber}?language={languageCode}.\n\nRequires the `items:read` scope.",
        "operationId": "Preview_ListItemTranslations",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicItemTranslationsResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:read"
      }
    },
    "/preview/items/{itemNumber}/translations/{languageCode}": {
      "put": {
        "tags": [
          "Items"
        ],
        "summary": "Set an item's translation",
        "description": "Replaces the item's translated texts in one language: name, description, short description and search-engine title and description. A field that is left out, null or empty is removed, and the item's own text is shown in its place — so send every field the language should keep. The language code is case-insensitive and a region is ignored (en-GB is en). Texts set on a channel publication are not language-specific and are shown in every language ahead of these translations.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_SetItemTranslation",
        "parameters": [
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item."
            }
          },
          {
            "name": "languageCode",
            "in": "path",
            "description": "ISO 639-1 code of an active language, e.g. en. Listed by GET /preview/items/{itemNumber}/translations.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "ISO 639-1 code of an active language, e.g. en. Listed by GET /preview/items/{itemNumber}/translations."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetItemTranslationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "A text is longer than 10 000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No item with that item number, or no active language with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/item-relations/batch": {
      "post": {
        "tags": [
          "Items"
        ],
        "summary": "Link many items to each other in one call",
        "description": "Adds up to 200 item relations per call — accessories, related items, cross-sells, spare parts. Both items are addressed by item number and must already exist.\n\nA relation that already exists (same source, target and type) is reported as `unchanged`, not as an error, so a migration can be re-run from the top. Like POST /preview/items/batch, a well-formed batch always answers 200 and every row carries its own `outcome`; re-send only the failed rows.\n\nRow errors: `ItemRelations.Bulk.UnknownSourceItem`, `ItemRelations.Bulk.UnknownTargetItem`, `ItemRelation.SelfReference`, `ItemRelation.InvalidType` and `ItemRelations.Bulk.GradedAlternativeNotSupported` — a graded alternative carries a grade and is linked one at a time in the app.\n\nRequires the `items:write` scope.",
        "operationId": "Preview_BatchItemRelations",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchItemRelationsRequest"
              },
              "examples": {
                "accessories": {
                  "summary": "Two accessories on a chair",
                  "value": {
                    "relations": [
                      {
                        "sourceItemNumber": "655-001",
                        "targetItemNumber": "100-21OIL",
                        "relationType": "Accessory"
                      },
                      {
                        "sourceItemNumber": "655-001",
                        "targetItemNumber": "100-FARSKINN",
                        "relationType": "Accessory"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchItemRelationsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'items:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "items:write"
      }
    },
    "/preview/channels/{channelCode}/media/{assetId}": {
      "delete": {
        "tags": [
          "Media"
        ],
        "summary": "Delete a media file",
        "description": "Removes the library record and the stored file. Nothing checks whether a page still references the url — a section pointing at a deleted file keeps its broken link, so look the file up in the pages that use it first. The deletion leaves a tombstone under GET /preview/deletions with resource 'media', so a client syncing with ?modifiedSince= sees it disappear.\n\nRequires the `media:write` scope.",
        "operationId": "Preview_DeleteMediaAsset",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the file belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the file belongs to."
            }
          },
          {
            "name": "assetId",
            "in": "path",
            "description": "The file's id.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The file's id.",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no file with that id in the channel.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'media:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "media:write"
      },
      "get": {
        "tags": [
          "Media"
        ],
        "summary": "Read one media file",
        "description": "Returns the library record for one file: the url it is served on plus its editorial metadata. This endpoint returns JSON, not the file itself — the bytes are fetched from url, which is served by the CDN and needs no API key. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `media:read` scope.",
        "operationId": "Preview_GetMediaAsset",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the file belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the file belongs to."
            }
          },
          {
            "name": "assetId",
            "in": "path",
            "description": "The file's id, as returned by the upload and by the listing.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The file's id, as returned by the upload and by the listing.",
              "format": "uuid"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicMediaAssetResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no file with that id in the channel.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'media:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "media:read"
      },
      "patch": {
        "tags": [
          "Media"
        ],
        "summary": "Update a media file's metadata",
        "description": "Partially updates one file's editorial metadata. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear title, altText or caption; folder and folderId cannot be null, and only one of them may be sent. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. The file itself cannot be replaced here — uploading a new file gives it a new url, so replacing one is an upload plus updating whatever referenced the old. Changing folder re-files the asset in the library but does not move the stored file: the url is unchanged, so links already pointing at it keep working. The folder a file was uploaded into therefore stays visible in its url.\n\nRequires the `media:write` scope.",
        "operationId": "Preview_PatchMediaAsset",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the file belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the file belongs to."
            }
          },
          {
            "name": "assetId",
            "in": "path",
            "description": "The file's id.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The file's id.",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchMediaAssetRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchMediaAssetRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a field present in it failed validation, folder was sent as null or with a value outside its list, or both folder and folderId were sent.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no file with that id in the channel.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'media:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "media:write"
      }
    },
    "/preview/channels/{channelCode}/media": {
      "get": {
        "tags": [
          "Media"
        ],
        "summary": "List a channel's media library",
        "description": "Returns the images uploaded to the channel, newest first. Each entry carries the url the file is served on — that is what goes into a page section or an article's featured image — and the id used to address the record on this API. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200. Delta sync: ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Deletions are not visible here: a deleted record is really gone, so it simply stops appearing, which is indistinguishable from \"unchanged\". Poll GET /preview/deletions?deletedSince= alongside this endpoint to learn what was removed. \n\nRequires the `media:read` scope.",
        "operationId": "Preview_ListMediaAssets",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel whose media library to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel whose media library to list."
            }
          },
          {
            "name": "folder",
            "in": "query",
            "description": "Restricts to one folder role: Hero, Banner, Sections, Content or Documents.",
            "schema": {
              "enum": [
                "Hero",
                "Banner",
                "Sections",
                "Content",
                "Documents"
              ],
              "type": "string",
              "description": "Restricts to one folder role: Hero, Banner, Sections, Content or Documents."
            }
          },
          {
            "name": "folderId",
            "in": "query",
            "description": "Restricts to one folder, by its id (folderId on each file).",
            "schema": {
              "type": "string",
              "description": "Restricts to one folder, by its id (folderId on each file).",
              "format": "uuid"
            }
          },
          {
            "name": "includeSubfolders",
            "in": "query",
            "description": "With folderId: also list files in its subfolders, at every level. Defaults to false.",
            "schema": {
              "type": "boolean",
              "description": "With folderId: also list files in its subfolders, at every level. Defaults to false."
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Matches file name, title and alt text, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches file name, title and alt text, case-insensitively and on partial words."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicMediaAssetResponse"
                }
              }
            }
          },
          "400": {
            "description": "folder got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'media:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "media:read"
      },
      "post": {
        "tags": [
          "Media"
        ],
        "summary": "Upload a file to the media library",
        "description": "Uploads a file as multipart/form-data. The field name is 'file'; everything else is a query parameter. Supported types: PNG, JPEG, GIF, WebP and SVG (max 10 MB), MP4 and WebM (max 50 MB), and PDF (max 20 MB). The size limit is per type: a 10 MB image is nearly always the camera original by mistake, while a 40 MB product video is ordinary. folder decides which part of the storefront the file is filed under and defaults to Content; it only affects filing and filtering, not what the file can be used for. The response is the same representation as GET on the file: its url goes into a page section or an article's featuredImageUrl, its id addresses the record here. The file itself is served by the CDN and needs no API key. This POST takes no Idempotency-Key — a multipart body cannot be hashed the way a JSON one can — so a retry after a network failure may create a second copy; list the folder and compare, or delete the duplicate. Known error codes: ChannelMediaAsset.EmptyFile, ChannelMediaAsset.FileTooLarge, ChannelMediaAsset.UnsupportedType.\n\n**Not idempotent.** A file upload carries no Idempotency-Key: the body cannot be buffered and hashed the way a JSON request can. Retrying after a network failure may therefore create a second copy — list the folder and compare before retrying, or delete the duplicate afterwards.\n\nRequires the `media:write` scope.",
        "operationId": "Preview_UploadMediaAsset",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel to upload into.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel to upload into."
            }
          },
          {
            "name": "folder",
            "in": "query",
            "description": "Where the file belongs: Hero, Banner, Sections, Content or Documents. Files it into that default folder. Defaults to Content.",
            "schema": {
              "type": "string",
              "description": "Where the file belongs: Hero, Banner, Sections, Content or Documents. Files it into that default folder. Defaults to Content."
            }
          },
          {
            "name": "folderId",
            "in": "query",
            "description": "The folder to file it into, by id. Cannot be combined with folder.",
            "schema": {
              "type": "string",
              "description": "The folder to file it into, by id. Cannot be combined with folder.",
              "format": "uuid"
            }
          },
          {
            "name": "title",
            "in": "query",
            "description": "Display name in the library. Defaults to the file name.",
            "schema": {
              "type": "string",
              "description": "Display name in the library. Defaults to the file name."
            }
          },
          {
            "name": "altText",
            "in": "query",
            "description": "Alt text for accessibility. Strongly recommended.",
            "schema": {
              "type": "string",
              "description": "Alt text for accessibility. Strongly recommended."
            }
          },
          {
            "name": "caption",
            "in": "query",
            "description": "Caption shown under the image.",
            "schema": {
              "type": "string",
              "description": "Caption shown under the image."
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicMediaAssetResponse"
                }
              }
            }
          },
          "400": {
            "description": "The file is empty, larger than the limit for its type, not one of the supported types, has no file name, folder got a value outside its list, or title, altText or caption is longer than allowed.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'media:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "media:write"
      }
    },
    "/preview/price-lists/{code}/lines/batch": {
      "post": {
        "tags": [
          "PriceLists"
        ],
        "summary": "Set many prices in a price list in one call",
        "description": "Sets up to 500 fixed prices per call, with the same rules as PUT /preview/price-lists/{code}/lines/{itemNumber}. Each line is identified by itemNumber, minQuantity and validFrom; a line that exists gets the new price, maxQuantity and validTo, and a line that does not is created.\n\nThe HTTP status describes the request, not the rows: a well-formed batch always answers 200, and every row carries its own `outcome` (`created`, `updated` or `failed`) plus an `error` when it failed. A bad row never blocks the rest — re-send only the failed rows. Row error codes: PriceListLine.UnknownItem, PriceListLine.DuplicateInBatch, PriceListLine.QuantityRange.Invalid, PriceListLine.ValidityRange.Invalid, PriceListLine.NotFixedPrice, PriceListLine.Ambiguous, and with `mode` set PriceListLine.AlreadyExists or PriceListLine.NoSuchLine.\n\n`mode` is `upsert` (default), `create` or `update`. An `Idempotency-Key` is required like on every POST under /preview.\n\nRequires the `price-lists:write` scope.",
        "operationId": "Preview_BatchUpsertPriceListLines",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "description": "Code of the price list, from GET /preview/price-lists.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the price list, from GET /preview/price-lists."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchUpsertPriceListLinesRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Two prices",
                  "value": {
                    "lines": [
                      {
                        "itemNumber": "670-00001",
                        "unitPrice": "249.00"
                      },
                      {
                        "itemNumber": "670-00002",
                        "unitPrice": "319.00"
                      }
                    ]
                  }
                },
                "price-change": {
                  "summary": "New prices from 1 January, next to today's",
                  "value": {
                    "lines": [
                      {
                        "itemNumber": "670-00001",
                        "unitPrice": "259.00",
                        "validFrom": "2027-01-01"
                      },
                      {
                        "itemNumber": "670-00001",
                        "unitPrice": "239.00",
                        "minQuantity": "10",
                        "validFrom": "2027-01-01"
                      }
                    ]
                  }
                },
                "update-only": {
                  "summary": "Change prices on lines that already exist",
                  "value": {
                    "mode": "update",
                    "lines": [
                      {
                        "itemNumber": "670-00001",
                        "unitPrice": "255.00"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchUpsertPriceListLinesResponse"
                }
              }
            }
          },
          "400": {
            "description": "The batch is empty or has more than 500 lines, a line lacks itemNumber or unitPrice, a value is negative, or mode is unknown.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No price list with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'price-lists:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "price-lists:write"
      }
    },
    "/preview/price-lists/{code}/lines": {
      "get": {
        "tags": [
          "PriceLists"
        ],
        "summary": "List the prices in a price list",
        "description": "Returns the price list's lines: one price per item, quantity break and start date. A line is identified by itemNumber, minQuantity and validFrom, so an item can have today's price and a price change from a later date as two lines. ?validOn= keeps only the lines that apply on that day, which is how to read the prices in force now. unitPrice is the price that applies: the price as entered on a Fixed line, or the most recently calculated price on a line priced from cost, the item's sales price or another price list (null until it has been calculated). Sorted by item number, minQuantity and validFrom. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `price-lists:read` scope.",
        "operationId": "Preview_ListPriceListLines",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "description": "Code of the price list, from GET /preview/price-lists.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the price list, from GET /preview/price-lists."
            }
          },
          {
            "name": "itemNumber",
            "in": "query",
            "description": "Only lines for this item number.",
            "schema": {
              "type": "string",
              "description": "Only lines for this item number."
            }
          },
          {
            "name": "validOn",
            "in": "query",
            "description": "Only lines that apply on this date (ISO 8601, e.g. 2026-10-01).",
            "schema": {
              "type": "string",
              "description": "Only lines that apply on this date (ISO 8601, e.g. 2026-10-01).",
              "format": "date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicPriceListLineResponse"
                }
              }
            }
          },
          "404": {
            "description": "No price list with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'price-lists:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "price-lists:read"
      }
    },
    "/preview/price-lists": {
      "get": {
        "tags": [
          "PriceLists"
        ],
        "summary": "List price lists",
        "description": "Returns the price lists with code, name, currency, validity and whether they are active. Inactive lists are included, so a list can be checked before it is switched on. The prices are under GET /preview/price-lists/{code}/lines. Sorted by code. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `price-lists:read` scope.",
        "operationId": "Preview_ListPriceLists",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicPriceListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'price-lists:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "price-lists:read"
      }
    },
    "/preview/price-lists/{code}/lines/{itemNumber}": {
      "put": {
        "tags": [
          "PriceLists"
        ],
        "summary": "Set an item's price in a price list",
        "description": "Sets the fixed price for the item in the price list and creates the line if it does not exist. The line is identified by the item, minQuantity and validFrom: omit both for the item's ordinary price, give minQuantity for a quantity break, and give validFrom for a price change from a later date — that becomes a line of its own and leaves the current price alone. On an existing line, maxQuantity and validTo are replaced by what the request says, so leaving them out removes a limit the line had. Only fixed prices are set here. A line priced from cost, the item's sales price or another price list answers 409 PriceListLine.NotFixedPrice rather than silently becoming a fixed price; change such a line in Fluit. To set many prices in one call, use POST /preview/price-lists/{code}/lines/batch. Known error codes: PriceList.NotFound, Item.NotFound, PriceListLine.QuantityRange.Invalid, PriceListLine.ValidityRange.Invalid, PriceListLine.NotFixedPrice, PriceListLine.Ambiguous.\n\nRequires the `price-lists:write` scope.",
        "operationId": "Preview_SetPriceListLine",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "description": "Code of the price list, from GET /preview/price-lists.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the price list, from GET /preview/price-lists."
            }
          },
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item to price.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item to price."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetPriceListLineRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "unitPrice is missing or negative, minQuantity is greater than maxQuantity, or validFrom is later than validTo.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No price list with that code, or no item with that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The line with this key is not a fixed price, or the price list has more than one line with this key.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'price-lists:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "price-lists:write"
      }
    },
    "/preview/purchase-orders/{orderNumber}/lines": {
      "post": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Add a line to a purchase order",
        "description": "Adds a line to an existing purchase order. If unitPrice is omitted the price is resolved from the supplier price list for the item. If unit is omitted the item's base unit is used (400 if the item has no base unit). The Location header points at the new line's address, purchase-orders/{orderNumber}/lines/{lineNumber}.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_AddPurchaseOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order to add the line to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order to add the line to."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddPurchaseOrderLineRequest"
              },
              "examples": {
                "default": {
                  "summary": "Add purchase order line",
                  "value": {
                    "itemNumber": "WIDGET-B",
                    "quantity": "25",
                    "unit": "st",
                    "unitPrice": "17.90"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPurchaseOrderLineResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, no item has that item number, or unit was omitted for an item that has no base unit.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is cancelled or closed, or otherwise in a state that no longer accepts new lines.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      },
      "get": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "List purchase order lines",
        "description": "Returns the lines on a purchase order, sorted by line number ascending. The same lines are also embedded in GET /preview/purchase-orders/{orderNumber}; this endpoint exists so that orders with many lines can be paged through. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `purchase-orders:read` scope.",
        "operationId": "Preview_ListPurchaseOrderLines",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order whose lines to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order whose lines to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicPurchaseOrderLineResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:read"
      }
    },
    "/preview/purchase-orders/{orderNumber}/cancel": {
      "post": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Cancel a purchase order",
        "description": "Cancels a purchase order. Only orders where nothing has been received can be cancelled — use close instead when goods have already arrived but no more are expected.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_CancelPurchaseOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order to cancel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order to cancel."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Goods have already been received on the order, or it is already closed or cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      }
    },
    "/preview/purchase-orders/{orderNumber}/close": {
      "post": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Close a purchase order",
        "description": "Closes a purchase order so that no further receipts are expected, even if quantities remain outstanding. Use this to settle short deliveries the supplier will not complete.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_ClosePurchaseOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order to close.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order to close."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is already closed or cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      }
    },
    "/preview/purchase-orders/{orderNumber}/confirm": {
      "post": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Confirm a purchase order",
        "description": "Records that the supplier has confirmed the order, moving it to Confirmed. Pass supplierReference to store the supplier's own order number from their confirmation. The request body is optional. This is a header-level status transition only: it does not populate the per-line confirmation fields (confirmedQuantity, confirmedUnitPrice, confirmedDeliveryDate), which stay null and are reserved for the structured confirmation flow that is not yet part of the public API. If the supplier confirmed different quantities or dates, patch the affected lines (PATCH /preview/purchase-orders/{orderNumber}/lines/{lineNumber}) — note that this changes what is ordered, so the deviation is applied rather than recorded alongside the original values.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_ConfirmPurchaseOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order the supplier has confirmed.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order the supplier has confirmed."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmPurchaseOrderRequest"
              },
              "examples": {
                "default": {
                  "summary": "Confirm with the supplier's order number",
                  "value": {
                    "supplierReference": "SO-99887"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "supplierReference is longer than 100 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is not Sent or PartiallyConfirmed, so there is nothing to confirm.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      }
    },
    "/preview/purchase-orders": {
      "post": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Create a purchase order",
        "description": "Creates a new purchase order for the authenticated tenant. Only supplierNumber is required; all other fields default from the supplier or tenant settings. The order is created in Draft status and is NOT sent to the supplier — call POST /preview/purchase-orders/{orderNumber}/send when it is ready to go out. orderNumber: if omitted a number is auto-generated from the tenant number sequence. Lines are created atomically with the order — if any line is rejected, no order is created. On a line, omit unitPrice to use the supplier price list, and omit unit to use the item's base unit (400 if the item has no base unit). The response body is the same representation as GET /preview/purchase-orders/{orderNumber}; the canonical URL is returned in the Location header and in links.self.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_CreatePurchaseOrder",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePurchaseOrderRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal — supplier and one line",
                  "value": {
                    "supplierNumber": "SUP-001",
                    "lines": [
                      {
                        "itemNumber": "WIDGET-A",
                        "quantity": "100"
                      }
                    ]
                  }
                },
                "full": {
                  "summary": "Full purchase order",
                  "value": {
                    "supplierNumber": "SUP-001",
                    "orderDate": "2026-08-01",
                    "expectedDeliveryDate": "2026-08-15",
                    "warehouseCode": "MAIN",
                    "currencyCode": "SEK",
                    "paymentTermCode": "NET30",
                    "deliveryTermCode": "DAP",
                    "supplierReference": "OUR-REF-4711",
                    "lines": [
                      {
                        "itemNumber": "WIDGET-A",
                        "quantity": "100",
                        "unit": "st",
                        "unitPrice": "42.50"
                      },
                      {
                        "itemNumber": "WIDGET-B",
                        "quantity": "25",
                        "expectedDate": "2026-08-22"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPurchaseOrderResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, one of the referenced codes (supplier, item, warehouse, terms, shipping method) does not exist, or a line omitted unit for an item that has no base unit.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order number passed in orderNumber is already in use.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      },
      "get": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "List purchase orders",
        "description": "Returns a paginated list of purchase orders for the authenticated tenant. The status filter is matched case-insensitively and an unknown value returns 400. ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Deletions are not visible here: a deleted record is really gone, so it simply stops appearing, which is indistinguishable from \"unchanged\". Poll GET /preview/deletions?deletedSince= alongside this endpoint to learn what was removed. Unlike sales orders, Draft purchase orders ARE included — an order created via POST /preview/purchase-orders starts in Draft and the caller has to be able to find it again. Sorted by order date descending, then order number. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `purchase-orders:read` scope.",
        "operationId": "Preview_ListPurchaseOrders",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filters on where the order stands in its lifecycle. Draft orders are included in this list, so ?status=Draft narrows to the ones not yet sent.",
            "schema": {
              "enum": [
                "Draft",
                "Sent",
                "PartiallyConfirmed",
                "Confirmed",
                "PartiallyReceived",
                "Received",
                "Closed",
                "Cancelled"
              ],
              "type": "string",
              "description": "Filters on where the order stands in its lifecycle. Draft orders are included in this list, so ?status=Draft narrows to the ones not yet sent."
            }
          },
          {
            "name": "supplierNumber",
            "in": "query",
            "description": "Returns only the orders placed with this supplier number.",
            "schema": {
              "type": "string",
              "description": "Returns only the orders placed with this supplier number."
            }
          },
          {
            "name": "orderDateFrom",
            "in": "query",
            "description": "Returns only orders dated on or after this date (ISO 8601 date).",
            "schema": {
              "type": "string",
              "description": "Returns only orders dated on or after this date (ISO 8601 date).",
              "format": "date"
            }
          },
          {
            "name": "orderDateTo",
            "in": "query",
            "description": "Returns only orders dated on or before this date (ISO 8601 date).",
            "schema": {
              "type": "string",
              "description": "Returns only orders dated on or before this date (ISO 8601 date).",
              "format": "date"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Matches order number and supplier reference, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches order number and supplier reference, case-insensitively and on partial words."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicPurchaseOrderListItem"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:read"
      }
    },
    "/preview/purchase-orders/{orderNumber}/lines/{lineNumber}": {
      "delete": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Delete a purchase order line",
        "description": "Removes a line from a purchase order and recalculates the order totals.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_DeletePurchaseOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order the line belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order the line belongs to."
            }
          },
          {
            "name": "lineNumber",
            "in": "path",
            "description": "Line number of the line, as reported in lineNumber on the order.",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "Line number of the line, as reported in lineNumber on the order.",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number, or no line with that line number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is closed or cancelled and no longer accepts changes to its lines.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      },
      "patch": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Update a purchase order line",
        "description": "Partially updates a purchase order line identified by its line number. Only provided fields are updated (JSON Merge Patch semantics); omitted fields are left unchanged. quantity, unitPrice and unit cannot be null; pass null for expectedDate, promisedDeliveryDate or notes to clear them. Line and order totals are recalculated automatically. The item on a line cannot be changed — delete the line and add a new one instead. Unlike the resource-level PATCH endpoints, fields this endpoint does not recognise are ignored rather than rejected, and field names are matched case-sensitively — send them exactly as documented.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_PatchPurchaseOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order the line belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order the line belongs to."
            }
          },
          {
            "name": "lineNumber",
            "in": "path",
            "description": "Line number of the line, as reported in lineNumber on the order.",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "Line number of the line, as reported in lineNumber on the order.",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchPurchaseOrderLineRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchPurchaseOrderLineRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, quantity, unitPrice or unit was sent as null, or a value falls outside its allowed range.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number, or no line with that line number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is closed or cancelled and no longer accepts changes to its lines.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      }
    },
    "/preview/purchase-orders/{orderNumber}": {
      "get": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Get a purchase order",
        "description": "Returns a single purchase order identified by its order number (exact match, case-sensitive), including all lines. Line numbers in the response are the business keys used by the line endpoints, e.g. PATCH /preview/purchase-orders/{orderNumber}/lines/{lineNumber}. confirmedQuantity, confirmedUnitPrice and confirmedDeliveryDate are null until the supplier has confirmed the line. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged. The validator follows the whole record, so a change to a nested part invalidates it too.\n\nRequires the `purchase-orders:read` scope.",
        "operationId": "Preview_GetPurchaseOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order to read. Matched exactly, case-sensitively.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order to read. Matched exactly, case-sensitively."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPurchaseOrderResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:read"
      },
      "patch": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Update a purchase order",
        "description": "Partially updates a purchase order header. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. orderNumber and supplierNumber cannot be changed — the order number is the resource's address, and changing supplier would invalidate the prices on every line. orderDate, warehouseCode and currencyCode cannot be set to null. Reference codes that do not exist return 400 with the offending field named. To change lines, use the line endpoints.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_PatchPurchaseOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order to update.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order to update."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchPurchaseOrderRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchPurchaseOrderRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a reference code does not exist, or orderDate, warehouseCode or currencyCode was sent as null.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is cancelled or closed and no longer accepts changes.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      }
    },
    "/preview/purchase-orders/{orderNumber}/lines/{lineNumber}/receive": {
      "post": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Receive goods on a purchase order line",
        "description": "Books received goods into stock against a purchase order line. This increases the on-hand quantity, creates an inventory transaction and advances the line and order status (PartiallyReceived, then Received once the full quantity has arrived). locationCode must be a location in the order's receiving warehouse; omit it to use that warehouse's default receiving location. unitCost records what the goods actually cost if it differs from the ordered price — it feeds the inventory valuation and must not be negative. serialNumber and batchNumber are stored on the receipt as supplied; they are not currently validated against the item's tracking type, so send the right one for the item. serialNumbers receives several serial-tracked units in one call: send one number per unit, as many numbers as the quantity, and omit serialNumber. Each number books its own receipt and its own stock record of one unit, exactly as a sequence of single-unit calls would — so at most 100 numbers fit in one call; split a larger delivery across several. Receiving is not reversible through this API; a retry with the same Idempotency-Key replays the original response instead of booking the goods twice. The response contains the created receipt id and the line as it stands after the receipt.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_ReceivePurchaseOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the purchase order the goods arrived on.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the purchase order the goods arrived on."
            }
          },
          {
            "name": "lineNumber",
            "in": "path",
            "description": "Line number of the line being received, as reported in lineNumber on the order.",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "Line number of the line being received, as reported in lineNumber on the order.",
              "format": "int32"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReceivePurchaseOrderLineRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Receive the full outstanding quantity",
                  "value": {
                    "quantity": "100"
                  }
                },
                "serial numbers": {
                  "summary": "Receive three serial-tracked units in one call",
                  "value": {
                    "quantity": "3",
                    "serialNumbers": [
                      "SN-100045",
                      "SN-100046",
                      "SN-100047"
                    ]
                  }
                },
                "full": {
                  "summary": "Partial receipt into a specific location with a batch number",
                  "value": {
                    "quantity": "40",
                    "locationCode": "A-01-02",
                    "unitCost": "42.75",
                    "batchNumber": "B-2026-08-14",
                    "notes": "Short delivery, remainder promised week 34"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceivePurchaseOrderLineResponse"
                }
              }
            }
          },
          "400": {
            "description": "The quantity is zero or less, it exceeds what is still outstanding on the line, unitCost is negative, or locationCode is not a location in the order's receiving warehouse.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number, or no line with that line number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is in a status that cannot receive goods, such as Draft or Cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      }
    },
    "/preview/purchase-orders/{orderNumber}/send": {
      "post": {
        "tags": [
          "PurchaseOrders"
        ],
        "summary": "Send a purchase order",
        "description": "Moves a purchase order from Draft to Sent. By default this only records that the order has gone out — nothing is emailed. That is the right behaviour when the order reaches the supplier over EDI or another channel you control. Set sendEmail=true to have Fluit email the purchase order PDF to the supplier; the address defaults to the supplier's purchaseOrderEmail and 400 is returned if neither that nor toEmail is set. Leave subject and message out to have Fluit write them from the tenant's email template, in the same language as the attached PDF. Sending an email is not reversible, so retries with the same Idempotency-Key replay the original response instead of sending again. The request body is optional; POSTing with no body sends without email.\n\nRequires the `purchase-orders:write` scope.",
        "operationId": "Preview_SendPurchaseOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the draft purchase order to send.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the draft purchase order to send."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendPurchaseOrderRequest"
              },
              "examples": {
                "mark-as-sent": {
                  "summary": "Mark as sent without emailing (default)",
                  "value": { }
                },
                "email": {
                  "summary": "Email the purchase order to the supplier",
                  "value": {
                    "sendEmail": true,
                    "subject": "Purchase order PO-2026-00042"
                  }
                },
                "email-in-english": {
                  "summary": "Email in English, letting Fluit write the subject and body",
                  "value": {
                    "sendEmail": true,
                    "language": "en"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "sendEmail is true but neither toEmail nor the supplier's purchaseOrderEmail is set, or the order has no lines to send.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No purchase order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is not in a status it can be sent from — it is cancelled, closed, or already sent.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'purchase-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "purchase-orders:write"
      }
    },
    "/preview/quotes/{quoteNumber}/accept": {
      "post": {
        "tags": [
          "Quotes"
        ],
        "summary": "Accept a quote",
        "description": "Records the customer's acceptance and stamps acceptedAt. Returns the quote so a storefront can show the confirmed state without a second request. Accepting does not create a sales order — call POST /preview/quotes/{quoteNumber}/convert-to-order for that. Keeping the two apart means an acceptance can be recorded the moment the customer clicks, and the order created when your flow is ready for it.\n\nRequires the `quotes:write` scope.",
        "operationId": "Preview_AcceptQuote",
        "parameters": [
          {
            "name": "quoteNumber",
            "in": "path",
            "description": "Quote number of the quote the customer accepted.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Quote number of the quote the customer accepted."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicQuoteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No quote with that quote number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The quote is not in Sent status.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'quotes:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "quotes:write"
      }
    },
    "/preview/quotes/{quoteNumber}/convert-to-order": {
      "post": {
        "tags": [
          "Quotes"
        ],
        "summary": "Convert a quote to a sales order",
        "description": "Creates a sales order from an accepted quote and returns the order in the same shape as GET /preview/orders/{orderNumber} — the Location header points at the new order, not back at the quote. The quote moves to Converted and its convertedToOrderNumber is set, so the link between the two is readable from either side. Only lines that reference an item are carried over. A sales order line requires an item, so free-text lines — services, one-off charges — are left behind: compare the returned order's lines against the quote's before relying on the totals. A quote consisting only of free-text lines cannot be converted. The quote must be Accepted, and can only be converted once. Known error codes: Quote.NotFound, Quote.NotAccepted, Quote.AlreadyConverted, Quote.NoConvertibleLines.\n\nRequires the `quotes:write` scope.",
        "operationId": "Preview_ConvertQuoteToOrder",
        "parameters": [
          {
            "name": "quoteNumber",
            "in": "path",
            "description": "Quote number of the accepted quote to turn into a sales order.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Quote number of the accepted quote to turn into a sales order."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicOrderDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "The quote is not Accepted, has already been converted, or has no line that can be carried into an order. Also returned when the tenant has no default warehouse or order type configured.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No quote with that quote number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'quotes:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "quotes:write"
      }
    },
    "/preview/quotes": {
      "post": {
        "tags": [
          "Quotes"
        ],
        "summary": "Create a sales quote",
        "description": "Creates a quote in Draft status and returns it in the same shape as GET /preview/quotes/{quoteNumber}. Every line must reference an existing item by itemNumber. Free-text lines are rejected: a sales order line requires an item, so such a line could never be carried into the order the quote is meant to become, and would silently disappear on conversion. description overrides the item's name on the printed quote. Lines carry the price you pass; they are not repriced from the customer's price list, but VAT is calculated per line from the customer's tax setup and the item's tax class. customerContactId must belong to customerNumber; a contact from another customer returns 400. The quote is not sent to the customer by creating it — use POST /preview/quotes/{quoteNumber}/send for that. Known error codes: Customer.NotFound, Item.NotFound, Quote.InvalidValidUntil.\n\nRequires the `quotes:write` scope.",
        "operationId": "Preview_CreateQuote",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateQuoteRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "One line",
                  "value": {
                    "customerNumber": "10001",
                    "lines": [
                      {
                        "itemNumber": "ART-1001",
                        "quantity": "10",
                        "unitPrice": "249.00"
                      }
                    ]
                  }
                },
                "full": {
                  "summary": "Titled quote with a volume discount",
                  "value": {
                    "customerNumber": "10001",
                    "title": "Autumn delivery",
                    "description": "Prices valid on the stated volume.",
                    "currencyCode": "SEK",
                    "validUntil": "2026-09-30",
                    "lines": [
                      {
                        "itemNumber": "ART-1001",
                        "quantity": "100",
                        "unitPrice": "249.00",
                        "description": "Widget, blue",
                        "unit": "st",
                        "discountPercent": "12.5"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicQuoteResponse"
                }
              }
            }
          },
          "400": {
            "description": "The customer or an item does not exist, customerContactId belongs to another customer, or validUntil falls before the quote date.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'quotes:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "quotes:write"
      },
      "get": {
        "tags": [
          "Quotes"
        ],
        "summary": "List sales quotes",
        "description": "Returns a paginated list of quotes, sorted by quoteNumber. ?modifiedSince= returns both created and modified quotes, so it can be used for delta sync; deletions are reported by GET /preview/deletions. Unlike sales orders, draft quotes are visible — a quote created through this API starts in Draft. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `quotes:read` scope.",
        "operationId": "Preview_ListQuotes",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches quote number and title, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches quote number and title, case-insensitively and on partial words."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on where the quote stands in its lifecycle.",
            "schema": {
              "enum": [
                "Draft",
                "Sent",
                "Accepted",
                "Declined",
                "Expired",
                "Converted"
              ],
              "type": "string",
              "description": "Filters on where the quote stands in its lifecycle."
            }
          },
          {
            "name": "customerNumber",
            "in": "query",
            "description": "Returns only the quotes made out to this customer number.",
            "schema": {
              "type": "string",
              "description": "Returns only the quotes made out to this customer number."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicQuoteResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'quotes:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "quotes:read"
      }
    },
    "/preview/quotes/{quoteNumber}/decline": {
      "post": {
        "tags": [
          "Quotes"
        ],
        "summary": "Decline a quote",
        "description": "Records the customer's rejection and stamps declinedAt. Returns the quote so a storefront can show the final state without a second request. Send a reason when you have one — it is what makes win/loss reporting usable.\n\nRequires the `quotes:write` scope.",
        "operationId": "Preview_DeclineQuote",
        "parameters": [
          {
            "name": "quoteNumber",
            "in": "path",
            "description": "Quote number of the quote the customer declined.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Quote number of the quote the customer declined."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeclineQuoteRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Decline without a reason",
                  "value": { }
                },
                "full": {
                  "summary": "Decline with a reason",
                  "value": {
                    "reason": "Chose a competitor on lead time"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicQuoteResponse"
                }
              }
            }
          },
          "400": {
            "description": "reason is longer than 1000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No quote with that quote number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The quote is not in Sent status, so there is nothing to decline.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'quotes:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "quotes:write"
      }
    },
    "/preview/quotes/{quoteNumber}": {
      "get": {
        "tags": [
          "Quotes"
        ],
        "summary": "Get a quote by quote number",
        "description": "Returns a quote with its lines and totals. Once the quote has been converted, convertedToOrderNumber points at the resulting sales order. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `quotes:read` scope.",
        "operationId": "Preview_GetQuote",
        "parameters": [
          {
            "name": "quoteNumber",
            "in": "path",
            "description": "Quote number of the quote to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Quote number of the quote to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicQuoteResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No quote with that quote number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'quotes:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "quotes:read"
      }
    },
    "/preview/quotes/{quoteNumber}/lines": {
      "get": {
        "tags": [
          "Quotes"
        ],
        "summary": "List quote lines",
        "description": "Returns the lines on a quote, sorted by line number ascending. The same lines are also embedded in GET /preview/quotes/{quoteNumber}; this endpoint exists so that quotes with many lines can be paged through rather than arriving as one unbounded array. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `quotes:read` scope.",
        "operationId": "Preview_ListQuoteLines",
        "parameters": [
          {
            "name": "quoteNumber",
            "in": "path",
            "description": "Quote number of the quote whose lines to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Quote number of the quote whose lines to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicQuoteLineResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No quote with that quote number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'quotes:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "quotes:read"
      }
    },
    "/preview/quotes/{quoteNumber}/send": {
      "post": {
        "tags": [
          "Quotes"
        ],
        "summary": "Send a quote",
        "description": "Moves the quote from Draft to Sent. mode=MarkAsSent (the default) only records the transition — use it when your own system delivers the quote to the customer. mode=Email makes Fluit render the quote PDF and email it. With mode=Email the mail leaves immediately and cannot be recalled, so treat a retry as a second email to the customer rather than a no-op.\n\nRequires the `quotes:write` scope.",
        "operationId": "Preview_SendQuote",
        "parameters": [
          {
            "name": "quoteNumber",
            "in": "path",
            "description": "Quote number of the draft quote to send.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Quote number of the draft quote to send."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendQuoteRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Mark as sent",
                  "value": { }
                },
                "full": {
                  "summary": "Let Fluit email the quote",
                  "value": {
                    "mode": "Email",
                    "toEmail": "inkop@kund.se",
                    "subject": "Your quote from Fluit",
                    "message": "Hi, please find our quote attached.",
                    "language": "sv"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "mode is Email but no recipient address could be resolved, the quote has no lines to send, or a field failed validation.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No quote with that quote number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The quote is not in Draft.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'quotes:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "quotes:write"
      }
    },
    "/preview/receipts/{receiptNumber}": {
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "Get a goods receipt by receipt number",
        "description": "Returns a goods receipt with its lines: what arrived, in what quantity, at what unit cost and into which location. Each line carries the purchase order number or transfer order number it received against, so the receipt can be matched back to the document that ordered it. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `receipts:read` scope.",
        "operationId": "Preview_GetReceipt",
        "parameters": [
          {
            "name": "receiptNumber",
            "in": "path",
            "description": "Receipt number of the goods receipt to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Receipt number of the goods receipt to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReceiptResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No goods receipt with that receipt number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'receipts:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "receipts:read"
      }
    },
    "/preview/receipts/{receiptNumber}/lines": {
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "List goods receipt lines",
        "description": "Returns the lines on a goods receipt, sorted by line number ascending. The same lines are also embedded in GET /preview/receipts/{receiptNumber}; this endpoint exists so that a goods receipt with many lines can be paged through rather than arriving as one unbounded array. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `receipts:read` scope.",
        "operationId": "Preview_ListReceiptLines",
        "parameters": [
          {
            "name": "receiptNumber",
            "in": "path",
            "description": "Receipt number of the goods receipt whose lines to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Receipt number of the goods receipt whose lines to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicReceiptLineResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No goods receipt with that receipt number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'receipts:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "receipts:read"
      }
    },
    "/preview/receipts": {
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "List goods receipts",
        "description": "Returns a paginated list of goods receipts, sorted by receiptNumber. A receipt records what physically arrived; each line points back to the purchase order line or transfer order line it received against. Receipts are created by receiving against a purchase order (POST /preview/purchase-orders/{orderNumber}/lines/{lineNumber}/receive) or a transfer order — there is no endpoint to create one directly, because a receipt without a document behind it is a stock adjustment. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `receipts:read` scope.",
        "operationId": "Preview_ListReceipts",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches the receipt number, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches the receipt number, case-insensitively and on partial words."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on how far the receipt has been processed.",
            "schema": {
              "enum": [
                "Draft",
                "InProgress",
                "Completed",
                "Cancelled"
              ],
              "type": "string",
              "description": "Filters on how far the receipt has been processed."
            }
          },
          {
            "name": "warehouseCode",
            "in": "query",
            "description": "Returns only the receipts booked into this warehouse.",
            "schema": {
              "type": "string",
              "description": "Returns only the receipts booked into this warehouse."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicReceiptResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'receipts:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "receipts:read"
      }
    },
    "/preview/channels/{channelCode}/redirects": {
      "post": {
        "tags": [
          "Redirects"
        ],
        "summary": "Create a URL redirect",
        "description": "Makes the channel's web shop send visitors from fromPath to toPath. Use it when an address stops working: after a move from another platform, or when a product is discontinued. fromPath is normalized (lowercase, leading slash, no trailing slash) and the response carries the stored form. A path can only be redirected once per channel: to change where it leads, update the existing redirect with PATCH instead of creating a second one. Known error codes: UrlRedirect.FromPathAlreadyExists, UrlRedirect.InvalidPath, UrlRedirect.InvalidToPath, UrlRedirect.SelfReference, UrlRedirect.InvalidStatusCode, UrlRedirect.FromPathTooLong, UrlRedirect.ToPathTooLong.\n\nRequires the `redirects:write` scope.",
        "operationId": "Preview_CreateRedirect",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel whose web shop should apply the redirect.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel whose web shop should apply the redirect."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRedirectRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Permanent redirect",
                  "value": {
                    "fromPath": "/old-product",
                    "toPath": "/products/new-product"
                  }
                },
                "full": {
                  "summary": "Temporary redirect to another site",
                  "value": {
                    "fromPath": "/campaign",
                    "toPath": "https://www.example.com/summer-campaign",
                    "statusCode": 302
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRedirectResponse"
                }
              }
            }
          },
          "400": {
            "description": "fromPath or toPath is missing or too long, toPath is neither a path starting with / nor an absolute http(s) URL, the redirect points to itself, or statusCode is not 301 or 302.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "UrlRedirect.FromPathAlreadyExists — the channel already redirects that path.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'redirects:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "redirects:write"
      },
      "get": {
        "tags": [
          "Redirects"
        ],
        "summary": "List a channel's URL redirects",
        "description": "Returns the redirects the channel's web shop applies before it matches a route: the ones created by hand or over this API, and the 301s Fluit records itself when a product, category or page changes slug. hitCount and lastHitAt show whether a redirect is still in use. Sorted by fromPath. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200. There is no delta sync for redirects: read the full list to reconcile.\n\nRequires the `redirects:read` scope.",
        "operationId": "Preview_ListRedirects",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel whose redirects to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel whose redirects to list."
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Matches fromPath and toPath, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches fromPath and toPath, case-insensitively and on partial words."
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filters on whether the redirect is active.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the redirect is active."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicRedirectResponse"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'redirects:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "redirects:read"
      }
    },
    "/preview/channels/{channelCode}/redirects/{id}": {
      "delete": {
        "tags": [
          "Redirects"
        ],
        "summary": "Delete a URL redirect",
        "description": "Removes the redirect, so fromPath answers with whatever the web shop has at that address, often a 404. To stop a redirect while keeping it for later, PATCH it with isActive: false instead.\n\nRequires the `redirects:write` scope.",
        "operationId": "Preview_DeleteRedirect",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the redirect belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the redirect belongs to."
            }
          },
          {
            "name": "id",
            "in": "path",
            "description": "Id of the redirect.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Id of the redirect.",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no redirect with that id in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'redirects:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "redirects:write"
      },
      "get": {
        "tags": [
          "Redirects"
        ],
        "summary": "Get a URL redirect",
        "description": "Returns one redirect, in the same shape as the list and as POST /preview/channels/{channelCode}/redirects.\n\nRequires the `redirects:read` scope.",
        "operationId": "Preview_GetRedirect",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the redirect belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the redirect belongs to."
            }
          },
          {
            "name": "id",
            "in": "path",
            "description": "Id of the redirect.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Id of the redirect.",
              "format": "uuid"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRedirectResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no redirect with that id in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'redirects:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "redirects:read"
      },
      "patch": {
        "tags": [
          "Redirects"
        ],
        "summary": "Update a URL redirect",
        "description": "Partially updates where a redirect leads, its status code and whether it is active. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. None of the fields can be set to null. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. fromPath cannot be changed: to redirect a different address, create a new redirect and delete this one. Known error codes: UrlRedirect.InvalidPath, UrlRedirect.InvalidToPath, UrlRedirect.SelfReference, UrlRedirect.InvalidStatusCode.\n\nRequires the `redirects:write` scope.",
        "operationId": "Preview_PatchRedirect",
        "parameters": [
          {
            "name": "channelCode",
            "in": "path",
            "description": "Code of the channel the redirect belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Code of the channel the redirect belongs to."
            }
          },
          {
            "name": "id",
            "in": "path",
            "description": "Id of the redirect.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Id of the redirect.",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchRedirectRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchRedirectRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a field was sent as null, toPath is neither a path starting with / nor an absolute http(s) URL, the redirect would point to itself, or statusCode is not 301 or 302.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No channel with that code, or no redirect with that id in it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'redirects:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "redirects:write"
      }
    },
    "/preview/reference/tenant-info": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "Get tenant info",
        "description": "Returns company details and base configuration (currency, language, timezone) for the authenticated tenant. Address fields use the same names as elsewhere in the API (street1, countryCode) and codes are ISO: countryCode is ISO 3166-1 alpha-2, baseCurrencyCode is ISO 4217 and defaultLanguageCode is ISO 639-1. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_GetTenantInfo",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTenantInfoResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/currencies": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List currencies",
        "description": "Returns all configured currencies. Use the code field as currencyCode in order creation. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListCurrencies",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicCurrencyResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/delivery-terms": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List delivery terms",
        "description": "Returns all delivery terms available for use as deliveryTermCode in order creation. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListDeliveryTerms",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicDeliveryTermResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/order-types": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List order types",
        "description": "Returns all order types available for use as orderTypeCode in order creation. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListOrderTypes",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicOrderTypeResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/payment-terms": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List payment terms",
        "description": "Returns all payment terms available for use as paymentTermCode in order creation. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListPaymentTerms",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicPaymentTermResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/shipping-methods": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List shipping methods",
        "description": "Returns shipping methods that have a code and can be referenced via shippingMethodCode in order creation. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListShippingMethods",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicShippingMethodResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/tax-classes": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List VAT classes",
        "description": "Returns the tenant's VAT classes together with the rate in effect today. An item carries only taxClassCode — join it against this list to get the rate. The rate depends on tax class, country and date, so it is not a property of the item. rate is null for a class with no rate configured in that country. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListTaxClasses",
        "parameters": [
          {
            "name": "countryCode",
            "in": "query",
            "description": "Returns the rates in effect in this country (ISO 3166-1 alpha-2), for example when invoicing cross-border. Defaults to the tenant's own country.",
            "schema": {
              "type": "string",
              "description": "Returns the rates in effect in this country (ISO 3166-1 alpha-2), for example when invoicing cross-border. Defaults to the tenant's own country."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicTaxClassResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "countryCode is not a valid ISO 3166-1 alpha-2 country code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/ticket-queues": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List ticket queues",
        "description": "Returns the active ticket queues (team workspaces) and their codes, for use as queueCode when routing a ticket with POST /preview/tickets/{ticketNumber}/queue or PATCH /preview/tickets/{ticketNumber}. Inactive queues are left out because they do not accept new tickets. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListTicketQueues",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicTicketQueueResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/units": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List units of measure",
        "description": "Returns all active units of measure. These are the valid values for unit on order lines. An item's own orderable units — the base unit plus any case/pallet units with their conversion factors — are returned by GET /preview/items/{itemNumber} in units[]. Unit codes are stored uppercase and matched case-insensitively. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListUnits",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicUnitResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/reference/warehouses": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List warehouses",
        "description": "Returns all active warehouses available for use as warehouseCode in order creation. Reference lists are bounded configuration data and are returned unpaginated. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the list is unchanged.\n\nRequires the `reference:read` scope.",
        "operationId": "Preview_ListWarehouses",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicWarehouseResponse"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'reference:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "reference:read"
      }
    },
    "/preview/returns/{returnNumber}/approve": {
      "post": {
        "tags": [
          "Returns"
        ],
        "summary": "Approve a customer return",
        "description": "Moves the return from Draft to Approved, which is the point at which the customer can be told to send the goods back. Returns the return so a storefront can show the approved state without a second request. No stock moves here — that happens on receipt.\n\nRequires the `returns:write` scope.",
        "operationId": "Preview_ApproveReturn",
        "parameters": [
          {
            "name": "returnNumber",
            "in": "path",
            "description": "Return number of the return to approve.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Return number of the return to approve."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnResponse"
                }
              }
            }
          },
          "400": {
            "description": "The return has no lines to approve.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No return with that return number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The return is not in Draft.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'returns:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "returns:write"
      }
    },
    "/preview/returns": {
      "post": {
        "tags": [
          "Returns"
        ],
        "summary": "Create a customer return",
        "description": "Registers a return against a sales order in Draft status and returns it in the same shape as GET /preview/returns/{returnNumber}. Omit lines to return the whole order — every delivered line is added at its delivered quantity, which is the common case for a webshop return. Pass lines to return specific quantities. The return and its lines are created in one transaction — if any line fails, nothing is created. Registering a return does not move stock: approve it, then receive it with POST /preview/returns/{returnNumber}/receive. Known error codes: SalesOrder.NotFound, SalesOrderLine.NotFound, SalesReturn.QuantityExceedsDelivered, SalesReturn.NoDeliveredLines.\n\nRequires the `returns:write` scope.",
        "operationId": "Preview_CreateReturn",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReturnRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Return the whole order",
                  "value": {
                    "orderNumber": "SO-2026-00042",
                    "reason": "CustomerRemorse"
                  }
                },
                "full": {
                  "summary": "Return two units of one line as damaged",
                  "value": {
                    "orderNumber": "SO-2026-00042",
                    "reason": "DamagedInTransit",
                    "warehouseCode": "HUVUD",
                    "rmaNumber": "RMA-9912",
                    "externalNotes": "Outer carton crushed on arrival.",
                    "lines": [
                      {
                        "orderLineNumber": 1,
                        "quantity": "2",
                        "condition": "Damaged",
                        "notes": "Both units dented"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnResponse"
                }
              }
            }
          },
          "400": {
            "description": "The sales order, one of its line numbers or the warehouse code does not exist, a line returns more than was delivered, or the order has no delivered lines to return.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'returns:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "returns:write"
      },
      "get": {
        "tags": [
          "Returns"
        ],
        "summary": "List customer returns",
        "description": "Returns a paginated list of customer returns, sorted by returnNumber. ?modifiedSince= returns both created and modified returns, so it can be used for delta sync; deletions are reported by GET /preview/deletions. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `returns:read` scope.",
        "operationId": "Preview_ListReturns",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches return number and RMA number, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches return number and RMA number, case-insensitively and on partial words."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on how far the return has been processed.",
            "schema": {
              "enum": [
                "Draft",
                "Approved",
                "Received",
                "CreditNoted",
                "Closed",
                "Cancelled"
              ],
              "type": "string",
              "description": "Filters on how far the return has been processed."
            }
          },
          {
            "name": "orderNumber",
            "in": "query",
            "description": "Returns only the returns raised against this sales order number.",
            "schema": {
              "type": "string",
              "description": "Returns only the returns raised against this sales order number."
            }
          },
          {
            "name": "customerNumber",
            "in": "query",
            "description": "Returns only the returns from this customer number.",
            "schema": {
              "type": "string",
              "description": "Returns only the returns from this customer number."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicReturnResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'returns:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "returns:read"
      }
    },
    "/preview/returns/{returnNumber}": {
      "get": {
        "tags": [
          "Returns"
        ],
        "summary": "Get a customer return by return number",
        "description": "Returns a customer return with its lines. Each line points back to the sales order line it came from and carries the condition the goods arrived in. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `returns:read` scope.",
        "operationId": "Preview_GetReturn",
        "parameters": [
          {
            "name": "returnNumber",
            "in": "path",
            "description": "Return number of the customer return to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Return number of the customer return to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No return with that return number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'returns:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "returns:read"
      }
    },
    "/preview/returns/{returnNumber}/lines": {
      "get": {
        "tags": [
          "Returns"
        ],
        "summary": "List return lines",
        "description": "Returns the lines on a return, sorted by line number ascending. The same lines are also embedded in GET /preview/returns/{returnNumber}; this endpoint exists so that a return with many lines can be paged through rather than arriving as one unbounded array. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `returns:read` scope.",
        "operationId": "Preview_ListReturnLines",
        "parameters": [
          {
            "name": "returnNumber",
            "in": "path",
            "description": "Return number of the return whose lines to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Return number of the return whose lines to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicReturnLineResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No return with that return number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'returns:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "returns:read"
      }
    },
    "/preview/returns/{returnNumber}/receive": {
      "post": {
        "tags": [
          "Returns"
        ],
        "summary": "Receive a customer return",
        "description": "Books the returned goods back into the return's warehouse and moves the return to Received. Only lines in Resellable condition go back into available stock; damaged defective and for-disposal lines are booked but not made available. Returns the return so the caller can see the received state without a second request. The resulting movements are readable from GET /preview/inventory/transactions with ?transactionType=Return. Receiving does not credit the customer — the credit note is raised separately.\n\nRequires the `returns:write` scope.",
        "operationId": "Preview_ReceiveReturn",
        "parameters": [
          {
            "name": "returnNumber",
            "in": "path",
            "description": "Return number of the approved return whose goods have arrived.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Return number of the approved return whose goods have arrived."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReceiveReturnRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Receive today",
                  "value": { }
                },
                "full": {
                  "summary": "Backdate the receipt",
                  "value": {
                    "receivedDate": "2026-08-05"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No return with that return number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The return has not been approved, or it has already been received.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'returns:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "returns:write"
      }
    },
    "/preview/orders/{orderNumber}/lines": {
      "post": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "Add a line to a sales order",
        "description": "Adds an order line to an existing sales order. If unitPrice is omitted the price is calculated automatically via the price engine. discountPercent must be between 0 and 100; it overrides the auto-calculated discount, omit it to apply the discount engine rules. The Location header points at the new line's address, orders/{orderNumber}/lines/{lineNumber}.\n\nRequires the `sales-orders:write` scope.",
        "operationId": "Preview_AddOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the sales order to add the line to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the sales order to add the line to."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddOrderLineRequest"
              },
              "examples": {
                "default": {
                  "summary": "Add order line",
                  "value": {
                    "itemNumber": "WIDGET-B",
                    "quantity": "5",
                    "unit": "st",
                    "unitPrice": "299.00"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicOrderLineResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, or no item has that item number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No sales order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is in a state that no longer accepts new lines, such as completed or cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:write"
      }
    },
    "/preview/orders/{orderNumber}/cancel": {
      "post": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "Cancel a sales order",
        "description": "Cancels a sales order. Only orders that have not been shipped can be cancelled.\n\nRequires the `sales-orders:write` scope.",
        "operationId": "Preview_CancelOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the sales order to cancel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the sales order to cancel."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No sales order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order has started shipping, or is already completed or cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:write"
      }
    },
    "/preview/orders": {
      "post": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "Create a sales order",
        "description": "Creates a new sales order for the authenticated tenant. customerNumber and at least one line are required (or set createAsDraft=true to create an empty draft); all other fields default from the customer or tenant settings. backorderBehavior: omit or null to inherit the tenant/customer configured default. Allowed values: CreateBackorder, CancelRemaining, HoldOrder. orderNumber: if omitted a number is auto-generated from the tenant number sequence. Use deliveryAddress to override the delivery address inline; if omitted the customer's default address is used. Optionally include lines to create order lines atomically with the order. Set createAsDraft=true to keep the order in Draft status (e.g. to add more lines via POST /orders/{orderNumber}/lines before placing). The response body is the same representation as GET /preview/orders/{orderNumber}; the canonical URL is returned in the Location header and in links.self.\n\nRequires the `sales-orders:write` scope.",
        "operationId": "Preview_CreateOrder",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOrderRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal — customer number and one line",
                  "value": {
                    "customerNumber": "CUST-001",
                    "lines": [
                      {
                        "itemNumber": "WIDGET-A",
                        "quantity": "10"
                      }
                    ]
                  }
                },
                "with-lines": {
                  "summary": "Order with lines and delivery address",
                  "value": {
                    "customerNumber": "CUST-001",
                    "orderDate": "2026-05-25",
                    "currencyCode": "SEK",
                    "customerReference": "PO-2026-042",
                    "lines": [
                      {
                        "itemNumber": "WIDGET-A",
                        "quantity": "10",
                        "unit": "st"
                      },
                      {
                        "itemNumber": "WIDGET-B",
                        "quantity": "5",
                        "unitPrice": "299.00"
                      }
                    ],
                    "deliveryAddress": {
                      "name": "Acme AB",
                      "street1": "Storgatan 1",
                      "postalCode": "11122",
                      "city": "Stockholm",
                      "countryCode": "SE"
                    }
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicOrderDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "No lines were provided and createAsDraft is false, a field failed validation, or one of the referenced codes (customer, item, warehouse, order type, terms, shipping method) does not exist.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order number passed in orderNumber is already in use.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:write"
      },
      "get": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "List sales orders",
        "description": "Returns a paginated list of sales orders for the authenticated tenant. Draft orders are excluded. The status filter is matched case-insensitively and an unknown value returns 400. Sorted by order date descending. channelCode on each order names the sales channel it came in through (null for orders entered in Fluit or created through this API), so ?channelCode= lists the webshop's orders. ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Deletions are not visible here: a deleted record is really gone, so it simply stops appearing, which is indistinguishable from \"unchanged\". Poll GET /preview/deletions?deletedSince= alongside this endpoint to learn what was removed. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `sales-orders:read` scope.",
        "operationId": "Preview_ListOrders",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filters on where the order stands in its fulfilment lifecycle.",
            "schema": {
              "enum": [
                "Placed",
                "Released",
                "Closed",
                "Cancelled"
              ],
              "type": "string",
              "description": "Filters on where the order stands in its fulfilment lifecycle."
            }
          },
          {
            "name": "customerNumber",
            "in": "query",
            "description": "Returns only the orders placed by this customer number.",
            "schema": {
              "type": "string",
              "description": "Returns only the orders placed by this customer number."
            }
          },
          {
            "name": "orderDateFrom",
            "in": "query",
            "description": "Returns only orders dated on or after this date (ISO 8601 date).",
            "schema": {
              "type": "string",
              "description": "Returns only orders dated on or after this date (ISO 8601 date).",
              "format": "date"
            }
          },
          {
            "name": "orderDateTo",
            "in": "query",
            "description": "Returns only orders dated on or before this date (ISO 8601 date).",
            "schema": {
              "type": "string",
              "description": "Returns only orders dated on or before this date (ISO 8601 date).",
              "format": "date"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Matches order number and customer reference, case-insensitively and on partial words — ORD-2024 finds every order whose number or reference contains it.",
            "schema": {
              "type": "string",
              "description": "Matches order number and customer reference, case-insensitively and on partial words — ORD-2024 finds every order whose number or reference contains it."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "channelCode",
            "in": "query",
            "description": "Returns only the orders that came in through this sales channel, e.g. the webshop. Matches channelCode on the order; the codes are listed by GET /preview/channels.",
            "schema": {
              "type": "string",
              "description": "Returns only the orders that came in through this sales channel, e.g. the webshop. Matches channelCode on the order; the codes are listed by GET /preview/channels."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicOrderListItem"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:read"
      }
    },
    "/preview/orders/{orderNumber}/lines/{lineNumber}": {
      "delete": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "Delete an order line",
        "description": "Removes a line from a sales order and releases any stock reservations for it. Order totals are recalculated automatically.\n\nRequires the `sales-orders:write` scope.",
        "operationId": "Preview_DeleteOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the sales order the line belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the sales order the line belongs to."
            }
          },
          {
            "name": "lineNumber",
            "in": "path",
            "description": "Line number of the line to remove, as reported in lineNumber on the order.",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "Line number of the line to remove, as reported in lineNumber on the order.",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No sales order with that order number, or no line with that line number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is closed or cancelled and no longer accepts changes to its lines.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:write"
      },
      "patch": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "Update an order line",
        "description": "Partially updates an order line identified by its line number. Only provided fields are updated (JSON Merge Patch semantics); omitted fields are left unchanged. quantity and unitPrice cannot be null; pass null for discountPercent, requestedDeliveryDate, notes or description to clear them. Clearing description makes the line fall back to the item name. Line totals and order totals are recalculated automatically. Unlike the resource-level PATCH endpoints, fields this endpoint does not recognise are ignored rather than rejected, and field names are matched case-sensitively — send them exactly as documented.\n\nRequires the `sales-orders:write` scope.",
        "operationId": "Preview_PatchOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the sales order the line belongs to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the sales order the line belongs to."
            }
          },
          {
            "name": "lineNumber",
            "in": "path",
            "description": "Line number of the line to update, as reported in lineNumber on the order.",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "Line number of the line to update, as reported in lineNumber on the order.",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchOrderLineRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchOrderLineRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, quantity or unitPrice was sent as null, or a value falls outside its allowed range.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No sales order with that order number, or no line with that line number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is closed or cancelled, or the quantity cannot change because a shipment line for it has already been picked.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:write"
      }
    },
    "/preview/orders/{orderNumber}": {
      "get": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "Get a sales order by order number",
        "description": "Returns the details of a sales order by its unique order number. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged. The validator follows the whole record, so a change to a nested part invalidates it too.\n\nRequires the `sales-orders:read` scope.",
        "operationId": "Preview_GetOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the sales order to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the sales order to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicOrderDetailResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No sales order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:read"
      }
    },
    "/preview/orders/{orderNumber}/shipments": {
      "get": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "List shipments for a sales order",
        "description": "Returns a paginated list of the shipments fulfilling the order, including carrier tracking numbers once booked. An order can have multiple shipments (partial deliveries) and a shipment can cover multiple orders (consolidated delivery) — only lines belonging to this order are included. Returns an empty items list if fulfilment has not started. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `sales-orders:read` scope.",
        "operationId": "Preview_GetOrderShipments",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the sales order whose shipments to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the sales order whose shipments to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicShipmentResponse"
                }
              }
            }
          },
          "404": {
            "description": "No sales order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:read"
      }
    },
    "/preview/orders/{orderNumber}/place": {
      "post": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "Place a sales order",
        "description": "Transitions a sales order from Draft to Placed, confirming it for processing. Business-rule violations return 400; the Problem Details response includes an `errors` extension array with one entry per violation, each containing a `code` and `description`. Known error codes: `SalesOrder.NoLinesInOrder` (order must have at least one line before it can be placed).\n\nRequires the `sales-orders:write` scope.",
        "operationId": "Preview_PlaceOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the draft sales order to place.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the draft sales order to place."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "A business rule blocks the order from being placed, such as having no lines.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No sales order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is not in Draft — it has already been placed, or it is cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:write"
      }
    },
    "/preview/orders/{orderNumber}/release": {
      "post": {
        "tags": [
          "SalesOrders"
        ],
        "summary": "Release a sales order",
        "description": "Transitions a sales order from Placed to Released, handing it to the warehouse. Runs the same rules as the Release button in Fluit.\n\n**Allocation.** Releasing turns the order's soft allocations into hard allocations on specific warehouse locations. Nothing more needs to be called for allocation. What happens to a line that is short depends on the order's backorder behaviour: *create backorder* (default) releases what is in stock and leaves the rest as a backorder that ships later; *cancel remaining* reduces the line to the allocated quantity; *hold order* blocks the release with `SalesOrder.NotFullyAllocated` until everything is covered.\n\n**Shipment.** If shipment automation is on for the tenant or the order type, releasing also creates the shipment in the same transaction. Check `GET /preview/orders/{orderNumber}/shipments` after releasing: if a shipment is listed, the warehouse can already pick and you should not call `POST /preview/shipments`. If none is listed, create it with `POST /preview/shipments`; that call answers `Shipment.NoHardAllocations` when every allocated unit is already on a shipment.\n\n**Retries.** Send an `Idempotency-Key`. A retry with the same key replays the first response without releasing again. A new request for an order that is already released answers 409 `SalesOrder.InvalidTransition`, so treat 409 on an order you released yourself as done.\n\nBusiness-rule violations return 400; the Problem Details response includes an `errors` extension array with one entry per violation, each containing a `code` and `description`. Known error codes: `SalesOrder.OnHold` (the order is on hold, for example a credit stop), `SalesOrder.LinesAwaitingMeasurement` (a configured line still carries a preliminary measurement; record the measurement, or release it in Fluit with a reason), `SalesOrder.NotFullyAllocated` (hold-order backorder behaviour and not everything is in stock), `SalesOrder.InvalidTransition` (409, the order is not in Placed).\n\nRequires the `sales-orders:write` scope.",
        "operationId": "Preview_ReleaseOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the placed sales order to release.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the placed sales order to release."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "A business rule blocks the release: the order is on hold, a line is waiting for an on-site measurement, or the order must ship complete and is not fully allocated.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No sales order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The order is not in Placed — it is still a draft, already released, closed or cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sales-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sales-orders:write"
      }
    },
    "/preview/shipments/{shipmentNumber}/packages": {
      "post": {
        "tags": [
          "Shipments"
        ],
        "summary": "Add a package to a shipment",
        "description": "Registers a physical package (parcel) on the shipment. Weight and dimensions are what the carrier prices and labels on, so set them when known — nShift rejects bookings for packages without a weight. A shipment needs at least one package before it can be packed. packageNumber is generated within the shipment if omitted.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_AddShipmentPackage",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the shipment to add the package to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the shipment to add the package to."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddShipmentPackageRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Weight only",
                  "value": {
                    "weightKg": "12.5"
                  }
                },
                "full": {
                  "summary": "Full parcel",
                  "value": {
                    "packageNumber": "PKG-1",
                    "weightKg": "12.5",
                    "lengthCm": "40",
                    "widthCm": "30",
                    "heightCm": "20",
                    "notes": "Fragile"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicShipmentPackageResponse"
                }
              }
            }
          },
          "400": {
            "description": "A weight or dimension is negative, or a field is longer than allowed.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The shipment has already shipped and can no longer be modified.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      },
      "get": {
        "tags": [
          "Shipments"
        ],
        "summary": "List the packages on a shipment",
        "description": "Returns the physical packages (parcels) registered on the shipment with their weight, dimensions and per-package tracking numbers. Tracking numbers are null until the shipment is booked with a carrier. Sorted by package number. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `shipments:read` scope.",
        "operationId": "Preview_ListShipmentPackages",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the shipment whose packages to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the shipment whose packages to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicShipmentPackageResponse"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:read"
      }
    },
    "/preview/shipments/{shipmentNumber}/book": {
      "post": {
        "tags": [
          "Shipments"
        ],
        "summary": "Book a shipment with the carrier",
        "description": "Books the shipment with the carrier behind its shipping method and returns the tracking number and the carrier's booking reference. Returns 200 rather than 204 because the tracking number is the point of the call — it is what gets sent to the customer. Emits the shipment.booked webhook. The call reaches an external carrier system, so it can fail for reasons outside Fluit: a rejected address, a service the receiver's country does not allow, or the carrier being unreachable. Booking is normally triggered automatically when packing is confirmed; call this explicitly to retry a failed booking or when the shipping method does not auto-book.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_BookShipment",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the packed shipment to book.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the packed shipment to book."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BookShipmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "The shipment has no shipping method or no packages, the carrier behind it is not configured for booking, or the carrier rejected the booking — its message is in the problem details.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The shipment is not packed.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      }
    },
    "/preview/shipments": {
      "post": {
        "tags": [
          "Shipments"
        ],
        "summary": "Create a shipment",
        "description": "Creates a shipment covering one or more sales orders and returns it in the same shape as GET /preview/shipments/{shipmentNumber}. The shipment starts in Released status with a line per allocated order line; drive it forward with the pick, pack, book, hand-over and mark-delivered actions. Orders must be released before a shipment can be created for them. Passing several order numbers consolidates them; the orders must agree on delivery address and shipping method. If releasing the order already created a shipment (shipment automation), every allocated unit is on that shipment and this call answers Shipment.NoHardAllocations; check GET /preview/orders/{orderNumber}/shipments first. Known error codes: SalesOrder.NotFound, SalesOrder.InvalidStatus (an order is not Released), SalesOrder.NoDeliveryAddress, Shipment.NoHardAllocations (nothing allocated is left to ship), Shipment.NoDeliverableLines (only service or non-stock lines), Shipment.NoShippingMethod, Shipment.DifferentCustomers, Shipment.DifferentAddresses, Shipment.ShipGroupOrderCannotBeConsolidated.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_CreateShipment",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateShipmentRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Single order",
                  "value": {
                    "orderNumbers": [
                      "SO-2026-00042"
                    ]
                  }
                },
                "full": {
                  "summary": "Consolidated with explicit carrier",
                  "value": {
                    "orderNumbers": [
                      "SO-2026-00042",
                      "SO-2026-00043"
                    ],
                    "shippingMethodCode": "DHL-PALL",
                    "notes": "Consolidated for weekly pickup"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicShipmentDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "orderNumbers is empty, the shipping method code does not exist, an order is not Released yet, or the consolidated orders disagree on customer or delivery address.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      },
      "get": {
        "tags": [
          "Shipments"
        ],
        "summary": "List shipments",
        "description": "Returns a paginated list of shipments, newest business key last — sorted by shipmentNumber so paging is deterministic. ?modifiedSince= returns both created and modified shipments, so it can be used for delta sync; deletions are reported by GET /preview/deletions. Each shipment carries all of its lines, including lines belonging to other orders on a consolidated shipment — use GET /preview/orders/{orderNumber}/shipments for the order-scoped view. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `shipments:read` scope.",
        "operationId": "Preview_ListShipments",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches shipment number and tracking number, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches shipment number and tracking number, case-insensitively and on partial words."
            }
          },
          {
            "name": "orderNumber",
            "in": "query",
            "description": "Returns only the shipments fulfilling this sales order number.",
            "schema": {
              "type": "string",
              "description": "Returns only the shipments fulfilling this sales order number."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on where the shipment stands in the pick-pack-ship flow.",
            "schema": {
              "enum": [
                "Hold",
                "Released",
                "Picking",
                "Picked",
                "ReadyForPickup",
                "Packing",
                "Packed",
                "Booked",
                "PickedUp",
                "InTransit",
                "Delivered",
                "Failed",
                "Cancelled"
              ],
              "type": "string",
              "description": "Filters on where the shipment stands in the pick-pack-ship flow."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicShipmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:read"
      }
    },
    "/preview/shipments/{shipmentNumber}": {
      "get": {
        "tags": [
          "Shipments"
        ],
        "summary": "Get a shipment by shipment number",
        "description": "Returns a shipment with its delivery address, lines and packages, plus the order numbers it fulfils — more than one on a consolidated shipment. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged. The validator follows the whole record, so a change to a line or a package invalidates it too.\n\nRequires the `shipments:read` scope.",
        "operationId": "Preview_GetShipment",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the shipment to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the shipment to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicShipmentDetailResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:read"
      },
      "patch": {
        "tags": [
          "Shipments"
        ],
        "summary": "Update a shipment",
        "description": "Partially updates a shipment. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. Use trackingNumber when the freight is booked outside Fluit, in the carrier's own portal or another shipping platform. When Fluit books the shipment (POST /preview/shipments/{shipmentNumber}/book) the number is set for you. Use shippingMethodCode when the carrier is only known once the goods have left — a forwarder choosing between carriers at dispatch, say. The shipping method carries the carrier and its tracking-link template, so setting both fields in the same call gives the customer a working tracking link (trackingUrl on GET). Codes that do not exist return 400 with the field named, and shippingMethodCode cannot be set to null. Changing the shipping method does not rebook the shipment or change the order's freight charge. Both fields can be changed in every status except in transit, including after the shipment is marked delivered, since the waybill often arrives afterwards. A shipment in transit cannot be changed and returns 409. shipmentNumber cannot be changed, because it is the resource's address. The delivery address and the status are not patchable here.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_PatchShipment",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the shipment to update.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the shipment to update."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchShipmentRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchShipmentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, trackingNumber is longer than 100 characters, shippingMethodCode does not exist, or shippingMethodCode was sent as null.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Shipment.CannotModifyShippedShipment — the shipment is in transit.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      }
    },
    "/preview/shipments/{shipmentNumber}/lines": {
      "get": {
        "tags": [
          "Shipments"
        ],
        "summary": "List the lines on a shipment",
        "description": "Returns every line on the shipment, across all orders it fulfils. Each line carries the orderNumber and orderLineNumber it originates from, so a consolidated shipment can be split back to its orders. Sorted by order number, then order line number. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `shipments:read` scope.",
        "operationId": "Preview_ListShipmentLines",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the shipment whose lines to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the shipment whose lines to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicShipmentLineResponse"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:read"
      }
    },
    "/preview/shipments/{shipmentNumber}/hand-over": {
      "post": {
        "tags": [
          "Shipments"
        ],
        "summary": "Hand a shipment over to the carrier",
        "description": "Records that the carrier has collected the shipment: status becomes PickedUp and shippedDate is stamped. This is what marks the goods as having left the warehouse, and it moves the underlying sales order lines to delivered.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_HandOverShipment",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the shipment the carrier has collected.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the shipment the carrier has collected."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The shipment is not ReadyForPickup, so there is nothing to hand over.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      }
    },
    "/preview/shipments/{shipmentNumber}/mark-delivered": {
      "post": {
        "tags": [
          "Shipments"
        ],
        "summary": "Mark a shipment as delivered",
        "description": "Records that the shipment reached the recipient: status becomes Delivered and deliveredDate is stamped. Use this when delivery confirmation comes from somewhere other than the carrier integration — a driver app, a signed proof of delivery, or a customer confirming pickup. Emits the shipment.delivered webhook.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_MarkShipmentDelivered",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the shipment that reached the recipient.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the shipment that reached the recipient."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The shipment has not been handed over to the carrier yet, or is already delivered.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      }
    },
    "/preview/shipments/{shipmentNumber}/pack": {
      "post": {
        "tags": [
          "Shipments"
        ],
        "summary": "Pack a shipment",
        "description": "Packs everything picked on the shipment into a package and, by default, confirms packing. Confirming triggers carrier booking when the shipping method is configured for it, so the response can come back with status Booked and a tracking number already set — read it with GET /preview/shipments/{shipmentNumber}. Returns 200 rather than 204 because the resulting status is the point of the call. Packing is applied line by line and persists as it goes, so the outcome can be partial: lines that could not be packed are reported in skipped[] with a reason. When anything was skipped the shipment is left unconfirmed — confirmed comes back false — so the remaining lines can be handled in the warehouse app and this call repeated. packageNumber may be omitted when the shipment has exactly one package. With several packages it is required — the call fails rather than picking one arbitrarily.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_PackShipment",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the picked shipment to pack.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the picked shipment to pack."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PackShipmentRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Single package, confirm and book",
                  "value": { }
                },
                "full": {
                  "summary": "Explicit package, leave unconfirmed",
                  "value": {
                    "packageNumber": "PKG-1",
                    "confirmWhenFullyPacked": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackShipmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "The shipment has no package to pack into — create one with POST /preview/shipments/{shipmentNumber}/packages.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number, or no package with that package number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The shipment has not been picked, or it has several packages and packageNumber was omitted.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      }
    },
    "/preview/shipments/{shipmentNumber}/pick": {
      "post": {
        "tags": [
          "Shipments"
        ],
        "summary": "Pick the lines on a shipment",
        "description": "Picks every outstanding quantity on the shipment from its allocated stock locations. Returns 200 rather than 204 because the outcome is partial by nature: lines that need a serial or batch number, or that lack stock at the allocated location, are reported in skipped[] with a reason and must be picked from the warehouse app. By default the shipment advances to Picked when nothing was skipped; pass completeWhenFullyPicked=false to keep it open and call again.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_PickShipment",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the released shipment to pick.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the released shipment to pick."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PickShipmentRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Pick and complete",
                  "value": { }
                },
                "full": {
                  "summary": "Pick without completing",
                  "value": {
                    "completeWhenFullyPicked": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PickShipmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The shipment has already shipped and can no longer be picked.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      }
    },
    "/preview/shipments/{shipmentNumber}/release": {
      "post": {
        "tags": [
          "Shipments"
        ],
        "summary": "Release a shipment to the warehouse",
        "description": "Moves a shipment from Hold to Released so the warehouse can start picking. Shipments created through this API are already Released — this endpoint exists for shipments put on hold.\n\nRequires the `shipments:write` scope.",
        "operationId": "Preview_ReleaseShipment",
        "parameters": [
          {
            "name": "shipmentNumber",
            "in": "path",
            "description": "Shipment number of the shipment on hold to release.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Shipment number of the shipment on hold to release."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The shipment could not be released because it has no lines to pick.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No shipment with that shipment number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The shipment is not on hold, so there is nothing to release.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'shipments:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "shipments:write"
      }
    },
    "/preview/suppliers": {
      "post": {
        "tags": [
          "Suppliers"
        ],
        "summary": "Create a supplier",
        "description": "Creates a new supplier for the authenticated tenant. Only name is required. supplierNumber: if omitted a number is auto-generated from the tenant number sequence. currencyCode defaults to the tenant base currency and determines the currency of purchase orders and supplier prices. paymentTermCode and deliveryTermCode must match existing reference data (400 if unknown) and become the defaults on purchase orders to this supplier. The response body is the same representation as GET /preview/suppliers/{supplierNumber}; the canonical URL is returned in the Location header and in links.self.\n\nRequires the `suppliers:write` scope.",
        "operationId": "Preview_CreateSupplier",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSupplierRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Minimal — name only",
                  "value": {
                    "name": "Nordic Components AB"
                  }
                },
                "full": {
                  "summary": "Full supplier",
                  "value": {
                    "name": "Nordic Components AB",
                    "supplierNumber": "SUP-001",
                    "organizationNumber": "5560001234",
                    "currencyCode": "SEK",
                    "purchaseOrderEmail": "order@nordic-components.se",
                    "phone": "+46812345678",
                    "street1": "Industrigatan 5",
                    "postalCode": "41250",
                    "city": "Göteborg",
                    "countryCode": "SE",
                    "paymentTermCode": "NET30",
                    "deliveryTermCode": "DAP",
                    "leadTimeDays": 14
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicSupplierResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, or the payment term or delivery term code does not exist.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The supplier number is already in use.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'suppliers:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "suppliers:write"
      },
      "get": {
        "tags": [
          "Suppliers"
        ],
        "summary": "List suppliers",
        "description": "Returns a paginated list of suppliers for the authenticated tenant. ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Deletions are not visible here: a deleted record is really gone, so it simply stops appearing, which is indistinguishable from \"unchanged\". Poll GET /preview/deletions?deletedSince= alongside this endpoint to learn what was removed. Sorted by supplierNumber ascending. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `suppliers:read` scope.",
        "operationId": "Preview_ListSuppliers",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches supplier number, name, organisation number and city, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches supplier number, name, organisation number and city, case-insensitively and on partial words."
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filters on whether the supplier is active.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the supplier is active."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicSupplierResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'suppliers:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "suppliers:read"
      }
    },
    "/preview/suppliers/{supplierNumber}": {
      "get": {
        "tags": [
          "Suppliers"
        ],
        "summary": "Get a supplier",
        "description": "Returns a single supplier identified by its supplier number (exact match, case-sensitive). Returns 404 Supplier.NotFound if no supplier has that number. paymentTermCode and deliveryTermCode can be passed straight back when creating a purchase order. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged. The validator follows the whole record, so a change to a nested part invalidates it too.\n\nRequires the `suppliers:read` scope.",
        "operationId": "Preview_GetSupplier",
        "parameters": [
          {
            "name": "supplierNumber",
            "in": "path",
            "description": "Supplier number of the supplier to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Supplier number of the supplier to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicSupplierResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No supplier with that supplier number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'suppliers:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "suppliers:read"
      },
      "patch": {
        "tags": [
          "Suppliers"
        ],
        "summary": "Update a supplier",
        "description": "Partially updates a supplier. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. supplierNumber cannot be changed — it is the resource's address. name and currencyCode cannot be set to null.\n\nRequires the `suppliers:write` scope.",
        "operationId": "Preview_PatchSupplier",
        "parameters": [
          {
            "name": "supplierNumber",
            "in": "path",
            "description": "Supplier number of the supplier to update.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Supplier number of the supplier to update."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchSupplierRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchSupplierRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a reference code does not exist, or name or currencyCode was sent as null.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No supplier with that supplier number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'suppliers:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "suppliers:write"
      }
    },
    "/preview/suppliers/{supplierNumber}/contacts": {
      "get": {
        "tags": [
          "Suppliers"
        ],
        "summary": "List supplier contacts",
        "description": "Returns the contact persons registered on a supplier, default contact first, then by name. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `suppliers:read` scope.",
        "operationId": "Preview_ListSupplierContacts",
        "parameters": [
          {
            "name": "supplierNumber",
            "in": "path",
            "description": "Supplier number of the supplier whose contacts to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Supplier number of the supplier whose contacts to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicSupplierContactResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No supplier with that supplier number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'suppliers:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "suppliers:read"
      }
    },
    "/preview/suppliers/{supplierNumber}/items": {
      "get": {
        "tags": [
          "Suppliers"
        ],
        "summary": "List supplier prices",
        "description": "Returns the supplier-specific purchase price, minimum order quantity, order multiple and lead time for each item this supplier can deliver. Prices are expressed in the supplier's currency (see currencyCode on the supplier). validFrom/validTo bound the price period; a row with both null is always valid. Sorted by itemNumber ascending. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `suppliers:read` scope.",
        "operationId": "Preview_ListSupplierItems",
        "parameters": [
          {
            "name": "supplierNumber",
            "in": "path",
            "description": "Supplier number of the supplier whose prices to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Supplier number of the supplier whose prices to list."
            }
          },
          {
            "name": "itemNumber",
            "in": "query",
            "description": "Looks up the price for one item, matched exactly.",
            "schema": {
              "type": "string",
              "description": "Looks up the price for one item, matched exactly."
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filters on whether the price row is still active, so retired rows can be excluded.",
            "schema": {
              "type": "boolean",
              "description": "Filters on whether the price row is still active, so retired rows can be excluded."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicSupplierItemResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No supplier with that supplier number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'suppliers:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "suppliers:read"
      }
    },
    "/preview/suppliers/{supplierNumber}/items/{itemNumber}": {
      "patch": {
        "tags": [
          "Suppliers"
        ],
        "summary": "Update a supplier's terms for an item",
        "description": "Updates the lead time, minimum order quantity and order multiple on the supplier's active price row for the item — the row GET /preview/suppliers/{supplierNumber}/items returns with isActive true. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. Decimals are sent as strings (\"12.5\"); numbers are accepted too. leadTimeDays is 0 to 365 days.\n\nMRP uses this lead time for the supplier it picks (an active purchase agreement's supplier, else the primary supplier) before the item-warehouse leadTimeDays; see GET /preview/item-warehouses for the full order. Purchase quantities are rounded up to minOrderQuantity and then to orderMultiple.\n\nRequires the `suppliers:write` scope.",
        "operationId": "Preview_PatchSupplierItem",
        "parameters": [
          {
            "name": "supplierNumber",
            "in": "path",
            "description": "Supplier number of the supplier.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Supplier number of the supplier."
            }
          },
          {
            "name": "itemNumber",
            "in": "path",
            "description": "Item number of the item.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Item number of the item."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchSupplierItemRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchSupplierItemRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, or a field failed validation: SupplierItem.LeadTimeDays.Invalid, SupplierItem.MinOrderQuantity.Invalid, SupplierItem.OrderMultiple.Invalid.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No supplier with that supplier number, no item with that item number, or the supplier has no active price row for the item.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'suppliers:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "suppliers:write"
      }
    },
    "/preview/deletions": {
      "get": {
        "tags": [
          "Sync"
        ],
        "summary": "List deleted records",
        "description": "Returns records that have been deleted, so an incremental sync can retire its local copies.\n\nThis endpoint exists because a deletion cannot be observed from the list endpoints. When a customer, supplier, purchase order or configuration is deleted the row is really gone, so no filter on GET /preview/customers (or any other collection) can surface it — it simply stops appearing, which is indistinguishable from \"unchanged since your last poll\". Every deletion is recorded here instead, in the same transaction as the deletion itself.\n\nCovers: `customers`, `items`, `suppliers`, `orders`, `purchase-orders`, `configurations`, `quotes`, `returns`, `shipments`, `invoices`, `item-channels`, `content-pages`, `media`, `item-assets`. Filter to one collection with `?resource=` (an unknown value returns 400 rather than an empty page).\n\n**Running a sync.** Poll `?modifiedSince=` on the list endpoints for creates and updates, and `?deletedSince=` here for removals, using the same timestamp for both. Results are sorted by `deletedDate` ascending, so take the highest `deletedDate` you have seen and pass it as the next `?deletedSince=`. Re-reading from a slightly earlier timestamp is safe: applying a deletion twice has no further effect.\n\n`businessKey` is the identifier the record had when it was deleted — customer number, item number, order number. For `item-channels`, `content-pages` and `media` the key is composite and written as the URL tail — `{itemNumber}/{channelCode}`, `{channelCode}/{slug}` and `{channelCode}/{id}` — so the removed record can be addressed directly. It is normally the field you stored, so match on it; `id` is there for clients that keyed on the GUID instead. Omitting `?deletedSince=` returns the full log from the beginning, which is rarely what you want after the first sync.\n\nPaginated response: `{ items, totalCount, page, pageSize, totalPages, hasPreviousPage, hasNextPage }`. `?page=` defaults to 1, `?pageSize=` to 50 and is capped at 200.\n\nRequires the `sync:read` scope.",
        "operationId": "Preview_ListDeletions",
        "parameters": [
          {
            "name": "deletedSince",
            "in": "query",
            "description": "Returns only records deleted at or after this instant (ISO 8601 UTC datetime). Omitting it returns the whole log from the beginning.",
            "schema": {
              "type": "string",
              "description": "Returns only records deleted at or after this instant (ISO 8601 UTC datetime). Omitting it returns the whole log from the beginning.",
              "format": "date-time"
            }
          },
          {
            "name": "resource",
            "in": "query",
            "description": "Limits the log to one collection, given by its path segment such as customers or purchase-orders. An unknown value returns 400 rather than an empty page.",
            "schema": {
              "type": "string",
              "description": "Limits the log to one collection, given by its path segment such as customers or purchase-orders. An unknown value returns 400 rather than an empty page."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicDeletionResponse"
                }
              }
            }
          },
          "400": {
            "description": "?resource= names a collection that is not covered by the deletion log.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'sync:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "sync:read"
      }
    },
    "/preview/tickets/{ticketNumber}/attachments": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Attach a file to a ticket",
        "description": "Uploads a file as multipart/form-data and attaches it to the ticket. The field name is 'file'; everything else is a query parameter. isInternal hides the file from the reporter in the customer portal and defaults to false — a file sent through the API belongs to the conversation unless you say otherwise. createdAt backdates the attachment to when it was attached in the system the ticket was migrated from, and only works on a ticket created through POST /preview/tickets/migrate; without it the file is dated now. File types are checked by extension against the same allowlist the customer portal uses, so executables are refused no matter who uploads them. Maximum 50 MB per file. Known error codes: Ticket.AttachmentTooLarge, Ticket.AttachmentTypeNotAllowed, Ticket.NotMigrated.\n\n**Not idempotent.** A file upload carries no Idempotency-Key: the body cannot be buffered and hashed the way a JSON request can. Retrying after a network failure may therefore create a second copy — list the folder and compare before retrying, or delete the duplicate afterwards.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_AddTicketAttachment",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to attach the file to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to attach the file to."
            }
          },
          {
            "name": "isInternal",
            "in": "query",
            "description": "Hide the file from the reporter in the customer portal. Defaults to false.",
            "schema": {
              "type": "boolean",
              "description": "Hide the file from the reporter in the customer portal. Defaults to false."
            }
          },
          {
            "name": "createdAt",
            "in": "query",
            "description": "When the file was attached in the source system (ISO 8601). Migrated tickets only.",
            "schema": {
              "type": "string",
              "description": "When the file was attached in the source system (ISO 8601). Migrated tickets only.",
              "format": "date-time"
            }
          },
          {
            "name": "description",
            "in": "query",
            "description": "Short description shown next to the file.",
            "schema": {
              "type": "string",
              "description": "Short description shown next to the file."
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddTicketAttachmentAddedAttachment"
                }
              }
            }
          },
          "400": {
            "description": "The file is empty, larger than 50 MB, of a type that cannot be attached, or the Content-Type header or description is longer than allowed.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "createdAt was given for a ticket that was not migrated.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/comments": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Add a message to a ticket",
        "description": "Appends a message to the ticket's conversation — the reporter answering a question, or an integration reporting what happened on its side. The message is visible to the reporter unless isInternal is true. authorName is who the message is from; it is free text because the sender is outside the ERP and has no user account here. The Location header points at the ticket's message collection, which is where the message can be read back — an individual message has no URL of its own.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_AddTicketComment",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to add the message to.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to add the message to."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddTicketCommentRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Reply from the reporter",
                  "value": {
                    "content": "Problemet kvarstår efter omstart."
                  }
                },
                "full": {
                  "summary": "Note from an integration",
                  "value": {
                    "content": "Fjärrdiagnostik körd: felkod E42 kvarstår.",
                    "authorName": "Servicerobot",
                    "isInternal": true
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddTicketCommentAddedComment"
                }
              }
            }
          },
          "400": {
            "description": "content is empty or longer than the allowed length.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      },
      "get": {
        "tags": [
          "Tickets"
        ],
        "summary": "List ticket messages",
        "description": "Returns the conversation on a ticket, oldest first — what the reporter wrote and what the agents answered. This is what a status page or a support widget shows under the ticket. Internal notes are left out unless ?includeInternal=true, which exists for integrations that mirror the whole ticket into another system. They are written by agents for agents and are not safe to show a customer. isFromAgent tells the two apart when rendering; the individual agent is not named. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `tickets:read` scope.",
        "operationId": "Preview_ListTicketComments",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket whose messages to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket whose messages to list."
            }
          },
          {
            "name": "includeInternal",
            "in": "query",
            "description": "Includes internal notes in the result. They are excluded by default and must never be shown to the reporter.",
            "schema": {
              "type": "boolean",
              "description": "Includes internal notes in the result. They are excluded by default and must never be shown to the reporter."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicTicketCommentResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:read"
      }
    },
    "/preview/tickets/{ticketNumber}/tags": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Tag a ticket",
        "description": "Adds a tag to the ticket for categorisation. Tags are free text and are created by being used — there is no tag register to keep in sync. Adding a tag the ticket already has changes nothing and still returns 200, so a classifier can re-run over the same ticket without special-casing. Returns the ticket with its tags.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_AddTicketTag",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to tag.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to tag."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddTicketTagRequest"
              },
              "examples": {
                "default": {
                  "summary": "Add a tag",
                  "value": {
                    "tag": "garanti"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "tag is missing or longer than 50 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/queue": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Move a ticket to a queue",
        "description": "Addresses the ticket to a team's queue so whoever is on duty can pick it up. This is how routing works through this API — assignment to a named agent is not exposed, because the agents are ERP users and this API does not expose users. Omitting queueCode, or sending it as null, takes the ticket out of its queue. The status is untouched: a queued ticket is still unhandled until someone takes it. Valid codes come from GET /preview/reference/ticket-queues. Returns the ticket in its new state. Known error codes: Ticket.CannotAssignToClosedTicket, Ticket.AlreadyCancelled.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_AssignTicketToQueue",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to move.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to move."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssignTicketToQueueRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Move to a queue",
                  "value": {
                    "queueCode": "SERVICE"
                  }
                },
                "full": {
                  "summary": "Take it out of its queue",
                  "value": {
                    "queueCode": null,
                    "note": "Hanteras direkt av säljaren."
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "queueCode names a queue that does not exist or is inactive.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is closed or cancelled and can no longer be moved.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/cancel": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Cancel a ticket",
        "description": "Cancels the ticket — the issue is no longer relevant, the request was withdrawn, or it was a duplicate. Nothing is deleted: the ticket stays readable and can be brought back with /reopen. Use /resolve instead when something was actually done; cancelled tickets are excluded from resolution statistics. Returns the ticket in its new state. Known error codes: Ticket.AlreadyClosed, Ticket.AlreadyCancelled.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_CancelTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to cancel.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to cancel."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CancelTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "No reason",
                  "value": { }
                },
                "full": {
                  "summary": "With a reason",
                  "value": {
                    "reason": "Dubblett av TKT-2026-00041."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "reason is longer than 1000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is already closed or cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/close": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Close a ticket",
        "description": "Closes the ticket and stamps closedAt. A ticket is normally resolved first — /resolve records how it was solved, which is what resolution statistics read — but closing an unresolved ticket is allowed for the cases where nothing was solved and nothing more will happen. A closed ticket can be brought back with /reopen. Returns the ticket in its new state. Known error codes: Ticket.AlreadyClosed, Ticket.AlreadyCancelled.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_CloseTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to close.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to close."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CloseTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "No note",
                  "value": { }
                },
                "full": {
                  "summary": "With a note",
                  "value": {
                    "note": "Kunden bekräftar att felet är borta."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "note is longer than 1000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is already closed or cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Submit a ticket",
        "description": "Creates a support ticket for the authenticated tenant — the endpoint behind a public contact or support form. The ticket lands in the same queue as tickets created inside the ERP and from the support mailbox. type is one of: ServiceRequest, Complaint, Support, Question (default Support). customerNumber is optional; supply it when the reporter is a known customer, and the ticket is linked to that customer. contactEmail is what the confirmation and the answer are sent to — a ticket without it can only be answered by phone. The response body is the same representation as GET /preview/tickets/{ticketNumber}; the canonical URL is returned in the Location header and in links.self.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_CreateTicket",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTicketRequest"
              },
              "examples": {
                "default": {
                  "summary": "Submit a ticket",
                  "value": {
                    "title": "Maskinen startar inte",
                    "description": "Efter senaste uppdateringen startar inte maskinen. Displayen är svart.",
                    "type": "Support",
                    "customerNumber": "CUST-001",
                    "contactName": "Anna Andersson",
                    "contactEmail": "anna@acme.example",
                    "contactPhone": "+46701234567"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, or no customer has the customer number given.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      },
      "get": {
        "tags": [
          "Tickets"
        ],
        "summary": "List tickets",
        "description": "Returns a paginated list of tickets, sorted by ticketNumber. Use ?customerNumber= to show a customer everything they have reported, ?queueCode= to mirror one team's workload, and ?open=true to skip the finished ones. An unknown customerNumber or queueCode returns an empty page rather than 404 — the filter narrows the collection, it does not address a resource. ?modifiedSince= (ISO 8601 UTC datetime) returns records created or changed at or after that instant, and is the intended way to run an incremental sync. A change anywhere inside the record counts: editing a line moves the parent's modifiedDate too, so no change can hide below the resource level. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200. Internal notes and the agent-facing history are not part of this representation; messages live under /preview/tickets/{ticketNumber}/comments.\n\nRequires the `tickets:read` scope.",
        "operationId": "Preview_ListTickets",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches ticket number, title and contact name, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches ticket number, title and contact name, case-insensitively and on partial words."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Returns only tickets in this status.",
            "schema": {
              "enum": [
                "New",
                "Triaged",
                "Assigned",
                "InProgress",
                "WaitingCustomer",
                "WaitingInternal",
                "OnHold",
                "Resolved",
                "Closed",
                "Cancelled"
              ],
              "type": "string",
              "description": "Returns only tickets in this status."
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Returns only tickets of this type.",
            "schema": {
              "enum": [
                "ServiceIncident",
                "ServiceRequest",
                "Maintenance",
                "Installation",
                "Inspection",
                "Rma",
                "Warranty",
                "Complaint",
                "Support",
                "Question",
                "Internal",
                "Firmware",
                "FeatureRequest"
              ],
              "type": "string",
              "description": "Returns only tickets of this type."
            }
          },
          {
            "name": "priority",
            "in": "query",
            "description": "Returns only tickets with this priority.",
            "schema": {
              "enum": [
                "Low",
                "Normal",
                "High",
                "Critical"
              ],
              "type": "string",
              "description": "Returns only tickets with this priority."
            }
          },
          {
            "name": "customerNumber",
            "in": "query",
            "description": "Returns only tickets belonging to this customer number.",
            "schema": {
              "type": "string",
              "description": "Returns only tickets belonging to this customer number."
            }
          },
          {
            "name": "queueCode",
            "in": "query",
            "description": "Returns only tickets addressed to this ticket queue code.",
            "schema": {
              "type": "string",
              "description": "Returns only tickets addressed to this ticket queue code."
            }
          },
          {
            "name": "open",
            "in": "query",
            "description": "true returns only tickets still being handled, false only the finished ones (Resolved, Closed, Cancelled). Omit for both.",
            "schema": {
              "type": "boolean",
              "description": "true returns only tickets still being handled, false only the finished ones (Resolved, Closed, Cancelled). Omit for both."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status=, ?type= or ?priority= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:read"
      }
    },
    "/preview/tickets/{ticketNumber}": {
      "get": {
        "tags": [
          "Tickets"
        ],
        "summary": "Get a ticket by ticket number",
        "description": "Returns the current state of a ticket belonging to the authenticated tenant — use it to show a submitter the status of what they reported. Internal notes and the agent-facing history are not part of this representation. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `tickets:read` scope.",
        "operationId": "Preview_GetTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:read"
      },
      "patch": {
        "tags": [
          "Tickets"
        ],
        "summary": "Update a ticket",
        "description": "Partially updates a ticket. Only provided fields are updated (JSON Merge Patch semantics). Omitted fields are left unchanged. Pass null to clear a nullable field. Unknown fields are rejected with 400, naming the field and listing the ones this endpoint accepts. ticketNumber cannot be changed — it is the resource's address. title and priority cannot be set to null. Status is not patchable: it changes through the action endpoints (/triage, /start, /resolve, /close and the rest), which enforce the allowed transitions and write the ticket's history. Changing priority or customer re-evaluates which SLA policy applies and moves the response and resolution deadlines accordingly. Reference keys that do not exist return 400 with the offending field named.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_PatchTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to update.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to update."
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchTicketRequest"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/PatchTicketRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, contains a field this endpoint does not have, a field failed validation, a customerNumber, queueCode or itemNumber does not exist, or title or priority was sent as null.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is closed or cancelled, so it can no longer be moved between queues.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/hold": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Pause a ticket",
        "description": "Moves the ticket to OnHold: work is deliberately postponed, without waiting for a particular reply or delivery. Use /wait-customer or /wait-internal when there is something specific being waited for — those states are what SLA reporting reads. Returns the ticket in its new state. Known error codes: Ticket.AlreadyClosed, Ticket.AlreadyCancelled, Ticket.InvalidStatusTransition.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_HoldTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to pause.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to pause."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HoldTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "No note",
                  "value": { }
                },
                "full": {
                  "summary": "With a note",
                  "value": {
                    "note": "Pausat till efter semesterperioden."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "note is longer than 1000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is resolved, closed or cancelled. A resolved ticket has to be reopened first.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/migrate": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Migrate a ticket from another system",
        "description": "Creates a ticket that already happened, with its history intact: the date it was created, the status it ended in, how it was resolved and the whole message thread. This is the endpoint for moving ticket history into Fluit when a support system is replaced — use POST /preview/tickets for tickets that are happening now. externalReference is required and must be unique; prefix it with the source system, e.g. 'SuperOffice:112614'. Posting the same reference twice does not create a second ticket — the response is 200 with the ticket that already exists and alreadyExisted = true, so an interrupted migration can simply be run again. The ticket sends no notifications and gets no SLA times: the reporter should not receive a confirmation for a ticket they filed two years ago, and our SLA policies never applied to it. Attach files with POST /preview/tickets/{ticketNumber}/attachments, passing the same original date so the files do not all look like they arrived on migration day. Known error codes: Ticket.ExternalReferenceRequired, Ticket.MigratedCreatedAtRequired, Ticket.MigratedTimestampBeforeCreation, Ticket.CustomerNotFound.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_MigrateTicket",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MigrateTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "A closed ticket with one message",
                  "value": {
                    "externalReference": "SuperOffice:112614",
                    "title": "Ingen bild på utgång 3",
                    "createdAt": "2024-12-17T09:43:29",
                    "description": "Matrisen ger ingen bild på utgång 3 efter uppdateringen.",
                    "status": "Closed",
                    "closedAt": "2024-12-20T16:05:00",
                    "contactName": "John Smith",
                    "contactEmail": "john@example.com",
                    "tags": [
                      "TightAV/Support"
                    ],
                    "messages": [
                      {
                        "content": "Matrisen ger ingen bild på utgång 3.",
                        "createdAt": "2024-12-17T09:43:29",
                        "authorName": "John Smith"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MigrateTicketResponse"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MigrateTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field failed validation, no customer has that customer number, or no active queue has that code.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/tags/{tag}": {
      "delete": {
        "tags": [
          "Tickets"
        ],
        "summary": "Remove a tag from a ticket",
        "description": "Removes a tag from the ticket. Removing a tag the ticket does not have is not an error — the end state is the same either way, so a retried call cannot fail on the second attempt. The 404 is about the ticket, not the tag.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_RemoveTicketTag",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to untag.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to untag."
            }
          },
          {
            "name": "tag",
            "in": "path",
            "description": "The tag to remove. Percent-encode it if it contains reserved characters.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The tag to remove. Percent-encode it if it contains reserved characters."
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/reopen": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Reopen a ticket",
        "description": "Brings a resolved, closed or cancelled ticket back to InProgress — the issue recurred, or it was not actually solved. resolvedAt, closedAt, resolutionType and resolutionNotes are cleared, and the resolution deadline starts over: the old target belonged to the finished round. The recorded root cause is kept — it is what was found out about the product, and it stays true whether or not the fix held. This is the way back into handling; the other transitions refuse to act on a resolved ticket precisely so the reset happens here. Returns the ticket in its new state. Known error code: Ticket.InvalidStatusTransition.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_ReopenTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to reopen.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to reopen."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReopenTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "No note",
                  "value": { }
                },
                "full": {
                  "summary": "With a note",
                  "value": {
                    "note": "Felet är tillbaka efter två veckor."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "note is longer than 1000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is not resolved, closed or cancelled — there is nothing to reopen.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/resolve": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Resolve a ticket",
        "description": "Marks the ticket resolved, stamps resolvedAt and records how it was solved. The SLA clock stops here and the resolution target is evaluated, so a ticket resolved past its deadline comes back with slaResolutionBreached = true. resolutionType is one of: Fixed, CannotReproduce, Duplicate, WontFix, CustomerResolved, RmaApproved, RmaRejected, Refunded, Replaced, ReturnVisitRequired, ResolvedByInstruction, FirmwareUpdate, ConfigurationChange, NoFaultFound. customerMessage is what the reporter is told, by email and in the customer portal; without it, resolutionNotes is used, as before. rootCause is the internal analysis and is not part of the ticket representation. Set notifyCustomer to false to resolve without emailing the reporter. Resolving does not close the ticket — the reporter may still come back. Close it with /close, or bring it back with /reopen. Returns the ticket in its new state. Known error codes: Ticket.AlreadyClosed, Ticket.AlreadyCancelled, Ticket.ResolutionRequiredToResolve.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_ResolveTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to resolve.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to resolve."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResolveTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Fixed",
                  "value": {
                    "resolutionType": "Fixed"
                  }
                },
                "full": {
                  "summary": "With notes and root cause",
                  "value": {
                    "resolutionType": "FirmwareUpdate",
                    "resolutionNotes": "Uppdaterad till firmware 2.4.2, felet går inte att återskapa.",
                    "rootCause": "Regression i 2.4.0 vid kall start."
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "resolutionType is missing or outside its list of values, or resolutionNotes, rootCause or customerMessage is longer than the allowed length.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is already closed or cancelled.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/start": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Start work on a ticket",
        "description": "Moves the ticket to InProgress — someone is now working on it. Returns the ticket in its new state, so a mirror does not need a second request. Known error codes: Ticket.AlreadyClosed, Ticket.AlreadyCancelled, Ticket.InvalidStatusTransition.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_StartTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to start work on.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to start work on."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "No note",
                  "value": { }
                },
                "full": {
                  "summary": "With a note",
                  "value": {
                    "note": "Tekniker tilldelad, felsökning påbörjad."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "note is longer than 1000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is resolved, closed or cancelled. A resolved ticket has to be reopened first.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/triage": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Triage a ticket",
        "description": "Sets the priority on a ticket that is still New and moves it to Triaged — the first pass a support desk makes over its inbox. priority is one of: Low, Normal, High, Critical. The priority decides which SLA policy applies, so the response and resolution deadlines are recalculated here. Returns the ticket in its new state. Known error code: Ticket.InvalidStatusTransition.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_TriageTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to triage.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to triage."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TriageTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Set the priority",
                  "value": {
                    "priority": "High"
                  }
                },
                "full": {
                  "summary": "With a note",
                  "value": {
                    "priority": "Critical",
                    "note": "Produktionsstopp hos kunden."
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "priority is missing or outside its list of values.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket has already left New — triage only applies to an unhandled ticket. Use PATCH to change the priority later.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/wait-customer": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Wait for the reporter",
        "description": "Moves the ticket to WaitingCustomer: the handler has asked a question and cannot continue until it is answered. The distinction from WaitingInternal matters for SLA reporting — waiting on the customer is not time the supplier owns. Returns the ticket in its new state. Known error codes: Ticket.AlreadyClosed, Ticket.AlreadyCancelled, Ticket.InvalidStatusTransition.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_WaitForCustomerOnTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to park.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to park."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WaitForCustomerOnTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "No note",
                  "value": { }
                },
                "full": {
                  "summary": "With a note",
                  "value": {
                    "note": "Bad kunden fotografera typskylten."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "note is longer than 1000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is resolved, closed or cancelled. A resolved ticket has to be reopened first.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/tickets/{ticketNumber}/wait-internal": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Wait for something internal",
        "description": "Moves the ticket to WaitingInternal: work is blocked on spare parts, a supplier delivery or another department rather than on the reporter. Returns the ticket in its new state. Known error codes: Ticket.AlreadyClosed, Ticket.AlreadyCancelled, Ticket.InvalidStatusTransition.\n\nRequires the `tickets:write` scope.",
        "operationId": "Preview_WaitInternalOnTicket",
        "parameters": [
          {
            "name": "ticketNumber",
            "in": "path",
            "description": "Ticket number of the ticket to park.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Ticket number of the ticket to park."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WaitInternalOnTicketRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "No note",
                  "value": { }
                },
                "full": {
                  "summary": "With a note",
                  "value": {
                    "note": "Väntar på reservdel, beräknad ankomst vecka 34."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "note is longer than 1000 characters.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No ticket with that ticket number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The ticket is resolved, closed or cancelled. A resolved ticket has to be reopened first.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'tickets:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "tickets:write"
      }
    },
    "/preview/transfer-orders": {
      "post": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "Create a transfer order",
        "description": "Creates a stock transfer between two warehouses in Draft status and returns it in the same shape as GET /preview/transfer-orders/{orderNumber}. The transfer and its lines are created in one transaction — if any line fails, nothing is created. Release it with POST /preview/transfer-orders/{orderNumber}/release to allocate stock and let the source warehouse pick. To move stock between locations inside one warehouse, use POST /preview/inventory/movements instead. Known error codes: Warehouse.NotFound, Item.NotFound, TransferOrder.SameWarehouse.\n\nRequires the `transfer-orders:write` scope.",
        "operationId": "Preview_CreateTransferOrder",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTransferOrderRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "One line",
                  "value": {
                    "fromWarehouseCode": "HUVUD",
                    "toWarehouseCode": "BUTIK-1",
                    "lines": [
                      {
                        "itemNumber": "ART-1001",
                        "quantity": "20"
                      }
                    ]
                  }
                },
                "full": {
                  "summary": "Dated with locations and carrier",
                  "value": {
                    "fromWarehouseCode": "HUVUD",
                    "toWarehouseCode": "BUTIK-1",
                    "requestedDate": "2026-09-01",
                    "shippingMethodCode": "INTERN-BIL",
                    "notes": "Weekly store replenishment",
                    "lines": [
                      {
                        "itemNumber": "ART-1001",
                        "quantity": "20",
                        "fromLocationCode": "A-01-01",
                        "toLocationCode": "INKOMMANDE"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "description": "URL of the newly created resource.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransferOrderResponse"
                }
              }
            }
          },
          "400": {
            "description": "A warehouse code or item number does not exist, the source and destination warehouse are the same, or a field failed validation.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:write"
      },
      "get": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "List transfer orders",
        "description": "Returns a paginated list of stock transfers, sorted by orderNumber. ?modifiedSince= returns both created and modified transfers, so it can be used for delta sync; deletions are reported by GET /preview/deletions. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `transfer-orders:read` scope.",
        "operationId": "Preview_ListTransferOrders",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches the order number, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches the order number, case-insensitively and on partial words."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on how far the transfer has got.",
            "schema": {
              "enum": [
                "Draft",
                "Placed",
                "Released",
                "Picking",
                "ReadyToShip",
                "InTransit",
                "PartiallyReceived",
                "Received",
                "Cancelled"
              ],
              "type": "string",
              "description": "Filters on how far the transfer has got."
            }
          },
          {
            "name": "fromWarehouseCode",
            "in": "query",
            "description": "Returns only the transfers leaving this warehouse.",
            "schema": {
              "type": "string",
              "description": "Returns only the transfers leaving this warehouse."
            }
          },
          {
            "name": "toWarehouseCode",
            "in": "query",
            "description": "Returns only the transfers arriving at this warehouse.",
            "schema": {
              "type": "string",
              "description": "Returns only the transfers arriving at this warehouse."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicTransferOrderResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:read"
      }
    },
    "/preview/transfer-orders/{orderNumber}": {
      "get": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "Get a transfer order by order number",
        "description": "Returns a stock transfer with its lines, including the requested, picked, shipped and received quantity per line — the four numbers that together say where the goods currently are. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `transfer-orders:read` scope.",
        "operationId": "Preview_GetTransferOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the transfer order to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the transfer order to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransferOrderResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No transfer order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:read"
      }
    },
    "/preview/transfer-orders/{orderNumber}/lines": {
      "get": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "List transfer order lines",
        "description": "Returns the lines on a transfer order, sorted by line number ascending. The same lines are also embedded in GET /preview/transfer-orders/{orderNumber}; this endpoint exists so that a transfer order with many lines can be paged through rather than arriving as one unbounded array. Returns 404 TransferOrder.NotFound if no transfer order has that number. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `transfer-orders:read` scope.",
        "operationId": "Preview_ListTransferOrderLines",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the transfer order whose lines to list.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the transfer order whose lines to list."
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicTransferOrderLineResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No transfer order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:read"
      }
    },
    "/preview/transfer-orders/{orderNumber}/lines/{lineNumber}/pick": {
      "post": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "Pick a transfer order line",
        "description": "Picks a quantity from a location in the source warehouse and returns the whole transfer order. The stock leaves the location immediately — two picks cannot take the same units — and the line's reservation shrinks by the picked quantity. Release the transfer first. A line can be picked in several calls, from several locations. When everything is picked the transfer moves to ReadyToShip; ship it to send what is picked. Undo picks with the unpick endpoint until the transfer ships. Known error codes: TransferOrder.NotFound, TransferOrderLine.NotFound, TransferOrder.CannotPickInStatus, TransferOrder.CannotPickMoreThanAvailable, TransferOrder.StockReservedForOtherOrders, TransferOrderPick.AmbiguousSource, Inventory.InsufficientStock.\n\nRequires the `transfer-orders:write` scope.",
        "operationId": "Preview_PickTransferOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the transfer order being picked.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the transfer order being picked."
            }
          },
          {
            "name": "lineNumber",
            "in": "path",
            "description": "Line number of the line being picked, as reported in lineNumber on the transfer order.",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "Line number of the line being picked, as reported in lineNumber on the transfer order.",
              "format": "int32"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PickTransferOrderLineRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Pick from a location",
                  "value": {
                    "quantity": "5",
                    "fromLocationCode": "A-01-02"
                  }
                },
                "batch": {
                  "summary": "Pick a specific batch",
                  "value": {
                    "quantity": "12",
                    "fromLocationCode": "BUF-02",
                    "batchNumber": "L-2026-14"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransferOrderResponse"
                }
              }
            }
          },
          "400": {
            "description": "The quantity is zero or less, exceeds what is left to pick, is more than is free to pick (the rest is reserved for other orders), or there is no stock of the item at fromLocationCode in the source warehouse.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No transfer order with that order number, or no line with that line number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The transfer is in a status that cannot be picked, or the location holds the item in several batches and batchNumber was not given.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:write"
      }
    },
    "/preview/transfer-orders/{orderNumber}/lines/{lineNumber}/receive": {
      "post": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "Receive a transfer order line",
        "description": "Books a received quantity into the destination warehouse and returns the whole transfer order so the caller can see the remaining quantities without a second request. Receive lines one at a time; partial receipts are allowed and move the transfer to PartiallyReceived until every line is fully received. You cannot receive more than was shipped — ship the quantity first. toLocationCode must be a location in the destination warehouse. serialNumbers receives several serial-tracked units in one call: send one number per unit, as many numbers as the quantity, and omit serialNumber. Each number books its own stock record of one unit, so at most 100 numbers fit in one call; split a larger transfer across several. Known error codes: TransferOrder.NotFound, TransferOrderLine.NotFound, TransferOrder.CannotReceiveInStatus, TransferOrder.CannotReceiveMoreThanShipped.\n\nRequires the `transfer-orders:write` scope.",
        "operationId": "Preview_ReceiveTransferOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the transfer order the goods arrived on.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the transfer order the goods arrived on."
            }
          },
          {
            "name": "lineNumber",
            "in": "path",
            "description": "Line number of the line being received, as reported in lineNumber on the transfer order.",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "Line number of the line being received, as reported in lineNumber on the transfer order.",
              "format": "int32"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReceiveTransferOrderLineRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Receive the full quantity",
                  "value": {
                    "quantity": "20"
                  }
                },
                "serial numbers": {
                  "summary": "Receive three serial-tracked units in one call",
                  "value": {
                    "quantity": "3",
                    "serialNumbers": [
                      "SN-100045",
                      "SN-100046",
                      "SN-100047"
                    ]
                  }
                },
                "full": {
                  "summary": "Partial receipt into a named location",
                  "value": {
                    "quantity": "12",
                    "toLocationCode": "INKOMMANDE",
                    "batchNumber": "L-2026-14"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransferOrderResponse"
                }
              }
            }
          },
          "400": {
            "description": "The quantity is zero or less, it exceeds what was shipped, or toLocationCode is not a location in the destination warehouse.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No transfer order with that order number, or no line with that line number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The transfer is in a status that cannot receive goods.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:write"
      }
    },
    "/preview/transfer-orders/{orderNumber}/release": {
      "post": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "Release a transfer order",
        "description": "Moves the transfer from Draft to Released, which allocates stock at the source warehouse and makes the lines available for picking.\n\nRequires the `transfer-orders:write` scope.",
        "operationId": "Preview_ReleaseTransferOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the draft transfer order to release.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the draft transfer order to release."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "The transfer is not in Draft, or it has no lines to release.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No transfer order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:write"
      }
    },
    "/preview/transfer-orders/{orderNumber}/ship": {
      "post": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "Ship a transfer order",
        "description": "Ships the picked quantities from the source warehouse: every line's shipped quantity is set to its picked quantity, the stock leaves the source warehouse and the transfer moves to InTransit. Lines that were not picked ship as zero, so pick before shipping if you expect the full quantity to move.\n\nRequires the `transfer-orders:write` scope.",
        "operationId": "Preview_ShipTransferOrder",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the picked transfer order to ship.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the picked transfer order to ship."
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "400": {
            "description": "Not every line has been picked, so there is nothing to ship on at least one of them.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No transfer order with that order number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The transfer is neither ReadyToShip nor Picking, so there is nothing to ship.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:write"
      }
    },
    "/preview/transfer-orders/{orderNumber}/lines/{lineNumber}/unpick": {
      "post": {
        "tags": [
          "TransferOrders"
        ],
        "summary": "Undo the picks on a transfer order line",
        "description": "Puts every picked unit on the line back on the location it was picked from, at the cost it had when picked, and reserves it for the line again. Returns the whole transfer order. Allowed until the transfer ships; a line with nothing picked is left as it is. Known error codes: TransferOrder.NotFound, TransferOrderLine.NotFound, TransferOrder.CannotUnpickInStatus.\n\nRequires the `transfer-orders:write` scope.",
        "operationId": "Preview_UnpickTransferOrderLine",
        "parameters": [
          {
            "name": "orderNumber",
            "in": "path",
            "description": "Order number of the transfer order.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Order number of the transfer order."
            }
          },
          {
            "name": "lineNumber",
            "in": "path",
            "description": "Line number of the line whose picks are undone.",
            "required": true,
            "schema": {
              "type": "integer",
              "description": "Line number of the line whose picks are undone.",
              "format": "int32"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Unique key (UUID recommended, max 255 chars) identifying this logical request. Reuse the same key when retrying after a network failure to get the original response replayed instead of creating a duplicate. Reusing a key with a different body returns 422. Responses are cached for 24 hours.",
            "required": true,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransferOrderResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No transfer order with that order number, or no line with that line number on it.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "The transfer has already shipped — picks can only be undone before shipping.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'transfer-orders:write' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "transfer-orders:write"
      }
    },
    "/preview/work-orders/{workOrderNumber}": {
      "get": {
        "tags": [
          "WorkOrders"
        ],
        "summary": "Get a work order by number",
        "description": "Read-only view of a work order: what is being produced, how much is done and when. Reporting output happens inside Fluit or in the mobile app. Responses carry a weak ETag; pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.\n\nRequires the `work-orders:read` scope.",
        "operationId": "Preview_GetWorkOrder",
        "parameters": [
          {
            "name": "workOrderNumber",
            "in": "path",
            "description": "Work order number of the work order to read.",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Work order number of the work order to read."
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a previous response. Returns 304 Not Modified with an empty body if the record has not changed since, which saves transferring the representation on a poll that finds nothing new.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWorkOrderResponse"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified",
            "headers": {
              "ETag": {
                "description": "Weak validator for this representation. Pass it back in If-None-Match to get 304 Not Modified while the record is unchanged.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "404": {
            "description": "No work order with that number.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'work-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "work-orders:read"
      }
    },
    "/preview/work-orders": {
      "get": {
        "tags": [
          "WorkOrders"
        ],
        "summary": "List work orders",
        "description": "Returns a paginated list of work orders, newest first. Read-only — production is planned and reported inside the ERP. ?modifiedSince= returns both created and modified work orders, so it can be used for delta sync. Fetch a single work order via its links.self. Response shape: { items: T[], totalCount: int, page: int, pageSize: int, totalPages: int, hasPreviousPage: bool, hasNextPage: bool }. Page is 1-based. Default pageSize is 50, maximum is 200.\n\nRequires the `work-orders:read` scope.",
        "operationId": "Preview_ListWorkOrders",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Matches work order number and title, case-insensitively and on partial words.",
            "schema": {
              "type": "string",
              "description": "Matches work order number and title, case-insensitively and on partial words."
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filters on how far production has got.",
            "schema": {
              "enum": [
                "Draft",
                "Planned",
                "Waiting",
                "Active",
                "Paused",
                "Completed",
                "Closed",
                "Cancelled",
                "Estimate"
              ],
              "type": "string",
              "description": "Filters on how far production has got."
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filters on what kind of work the order covers.",
            "schema": {
              "enum": [
                "Manufacturing",
                "Project",
                "Service",
                "Maintenance"
              ],
              "type": "string",
              "description": "Filters on what kind of work the order covers."
            }
          },
          {
            "name": "outputItemNumber",
            "in": "query",
            "description": "Returns only the work orders producing this item.",
            "schema": {
              "type": "string",
              "description": "Returns only the work orders producing this item."
            }
          },
          {
            "name": "modifiedSince",
            "in": "query",
            "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
            "schema": {
              "type": "string",
              "description": "Returns only records created or changed at or after this instant (ISO 8601 UTC datetime). A change anywhere inside the record counts, including on its lines.",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page to return, 1-based. Default 1.",
            "schema": {
              "type": "integer",
              "description": "Page to return, 1-based. Default 1.",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Number of records per page. Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Number of records per page. Default 50, max 200.",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResult_PublicWorkOrderResponse"
                }
              }
            }
          },
          "400": {
            "description": "?status= or ?type= got a value outside its list.",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests remaining in the current rate-limit window.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds since epoch) at which the current rate-limit window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              }
            }
          },
          "403": {
            "description": "The credential does not carry the 'work-orders:read' scope."
          }
        },
        "security": [
          { },
          { }
        ],
        "x-required-scope": "work-orders:read"
      }
    }
  },
  "components": {
    "schemas": {
      "AddItemCategoryRequest": {
        "required": [
          "categoryCode"
        ],
        "type": "object",
        "properties": {
          "categoryCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Code of the category to add, from GET /preview/categories. The category must be active."
          },
          "sortOrder": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Position among the item's categories. Defaults to after the item's last category.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AddOrderLineRequest": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "minLength": 1,
            "type": "string",
            "description": "Item number of an existing item."
          },
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Ordered quantity. Must be greater than zero.",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Overrides the item's default sales price. Omit to use the item's default.",
            "format": "double",
            "nullable": true
          },
          "discountPercent": {
            "maximum": 100,
            "minimum": 0,
            "type": "number",
            "description": "Line discount in percent (0–100).",
            "format": "double",
            "nullable": true
          },
          "unit": {
            "maxLength": 20,
            "type": "string",
            "description": "Unit of measure code, e.g. `st`, `kg`. Defaults to the item's base unit.",
            "nullable": true
          },
          "requestedDeliveryDate": {
            "type": "string",
            "description": "Requested delivery date for this line.",
            "format": "date",
            "nullable": true
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text line notes.",
            "nullable": true
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Customer-facing line text. Defaults to the item name when omitted.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AddPurchaseOrderLineRequest": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "minLength": 1,
            "type": "string",
            "description": "Item number of an existing item."
          },
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Ordered quantity. Must be greater than zero.",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Overrides the supplier's price for the item. Omit to use the supplier price list.",
            "format": "double",
            "nullable": true
          },
          "unit": {
            "maxLength": 20,
            "type": "string",
            "description": "Unit of measure code, e.g. `st`, `kg`. Defaults to the item's base unit.",
            "nullable": true
          },
          "expectedDate": {
            "type": "string",
            "description": "Expected delivery date for this line.",
            "format": "date",
            "nullable": true
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text line notes.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AddShipmentPackageRequest": {
        "type": "object",
        "properties": {
          "packageNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Package number. Auto-generated within the shipment if omitted.",
            "nullable": true
          },
          "weightKg": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "Weight in kilograms.",
            "format": "double",
            "nullable": true
          },
          "lengthCm": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "Length in centimetres.",
            "format": "double",
            "nullable": true
          },
          "widthCm": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "Width in centimetres.",
            "format": "double",
            "nullable": true
          },
          "heightCm": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "Height in centimetres.",
            "format": "double",
            "nullable": true
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text notes on the package.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AddTicketAttachmentAddedAttachment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the stored attachment.",
            "format": "uuid"
          },
          "fileName": {
            "type": "string",
            "description": "The file name as stored, with any path parts removed.",
            "nullable": true
          },
          "sizeBytes": {
            "type": "integer",
            "description": "Size of the stored file.",
            "format": "int64"
          }
        },
        "additionalProperties": false
      },
      "AddTicketCommentAddedComment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal identifier of the message that was added.",
            "format": "uuid"
          }
        },
        "additionalProperties": false
      },
      "AddTicketCommentRequest": {
        "required": [
          "content"
        ],
        "type": "object",
        "properties": {
          "content": {
            "maxLength": 8000,
            "minLength": 1,
            "type": "string",
            "description": "The message body."
          },
          "authorName": {
            "maxLength": 200,
            "type": "string",
            "description": "Name of the person the message is from. Shown next to the message.",
            "nullable": true
          },
          "isInternal": {
            "type": "boolean",
            "description": "Marks the message as an internal note, hidden from the reporter. Defaults to false —\na message from an integration is normally the reporter answering.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AddTicketTagRequest": {
        "required": [
          "tag"
        ],
        "type": "object",
        "properties": {
          "tag": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "The tag to add, e.g. `garanti` or `fältservice`."
          }
        },
        "additionalProperties": false
      },
      "AssignTicketToQueueRequest": {
        "type": "object",
        "properties": {
          "queueCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the queue to move the ticket to, from GET /preview/reference/ticket-queues.\nPass `null` to take the ticket out of its queue.",
            "nullable": true
          },
          "note": {
            "maxLength": 1000,
            "type": "string",
            "description": "Note stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BackorderBehavior": {
        "enum": [
          "CreateBackorder",
          "CancelRemaining",
          "HoldOrder"
        ],
        "type": "string"
      },
      "BatchItemRelationsRelationRow": {
        "required": [
          "relationType",
          "sourceItemNumber",
          "targetItemNumber"
        ],
        "type": "object",
        "properties": {
          "sourceItemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "The item the relation is shown on."
          },
          "targetItemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "The item it points to."
          },
          "relationType": {
            "maxLength": 30,
            "minLength": 1,
            "type": "string",
            "description": "`Related`, `Accessory`, `CrossSell`, `UpSell`, `SparePart` or\n            `Replacement`. Graded alternatives are not accepted in a batch."
          },
          "sortOrder": {
            "type": "integer",
            "description": "Position among the source item's relations of this type. Defaults to last.",
            "format": "int32",
            "nullable": true
          },
          "isBidirectional": {
            "type": "boolean",
            "description": "Also show the relation from the target item's side."
          }
        },
        "additionalProperties": false
      },
      "BatchItemRelationsRequest": {
        "required": [
          "relations"
        ],
        "type": "object",
        "properties": {
          "relations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchItemRelationsRelationRow"
            },
            "description": "The relations to add. At most 200 per call."
          }
        },
        "additionalProperties": false
      },
      "BatchItemRelationsResponse": {
        "type": "object",
        "properties": {
          "createdCount": {
            "type": "integer",
            "format": "int32"
          },
          "unchangedCount": {
            "type": "integer",
            "format": "int32"
          },
          "failedCount": {
            "type": "integer",
            "format": "int32"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchItemRelationsRowResult"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchItemRelationsRowError": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchItemRelationsRowResult": {
        "type": "object",
        "properties": {
          "index": {
            "type": "integer",
            "format": "int32"
          },
          "sourceItemNumber": {
            "type": "string",
            "nullable": true
          },
          "targetItemNumber": {
            "type": "string",
            "nullable": true
          },
          "outcome": {
            "type": "string",
            "description": "`created`, `unchanged` (it already existed) or `failed`.",
            "nullable": true
          },
          "error": {
            "$ref": "#/components/schemas/BatchItemRelationsRowError"
          }
        },
        "additionalProperties": false
      },
      "BatchPatchItemWarehousesRequest": {
        "required": [
          "itemWarehouses"
        ],
        "type": "object",
        "properties": {
          "itemWarehouses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchPatchItemWarehousesRow"
            },
            "description": "The rows to update. At most 200 per call."
          }
        },
        "additionalProperties": false
      },
      "BatchPatchItemWarehousesResponse": {
        "type": "object",
        "properties": {
          "updatedCount": {
            "type": "integer",
            "format": "int32"
          },
          "failedCount": {
            "type": "integer",
            "format": "int32"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchPatchItemWarehousesRowResult"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchPatchItemWarehousesRow": {
        "required": [
          "itemNumber",
          "warehouseCode"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Item number. Required — with warehouseCode it identifies the row."
          },
          "warehouseCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Warehouse code. Required — with itemNumber it identifies the row."
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the item is active in this warehouse. Cannot be null.",
            "nullable": true
          },
          "minQuantity": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Reorder point. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "maxQuantity": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Maximum stock level. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "reorderQuantity": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Quantity ordered by `FixedReorderQuantity`. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "safetyStock": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Safety stock. Pass `null` to let MRP use the calculated safety stock.",
            "format": "double",
            "nullable": true
          },
          "leadTimeDays": {
            "maximum": 365,
            "minimum": 0,
            "type": "integer",
            "description": "Lead time in calendar days in this warehouse. Pass `null` to clear.",
            "format": "int32",
            "nullable": true
          },
          "lotSizing": {
            "$ref": "#/components/schemas/PublicLotSizingPolicy"
          },
          "supplyPolicy": {
            "$ref": "#/components/schemas/PublicSupplyPolicy"
          },
          "replenishmentType": {
            "$ref": "#/components/schemas/PublicReplenishmentType"
          },
          "importance": {
            "$ref": "#/components/schemas/PublicItemImportance"
          },
          "serviceLevelOverride": {
            "type": "number",
            "description": "Service level between 0 and 1. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "transferFromWarehouseCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Source warehouse for `Transfer`. Pass `null` to clear.",
            "nullable": true
          },
          "transferLeadTimeDays": {
            "maximum": 365,
            "minimum": 0,
            "type": "integer",
            "description": "Transport time in days from the source warehouse. Pass `null` to clear.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchPatchItemWarehousesRowError": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchPatchItemWarehousesRowResult": {
        "type": "object",
        "properties": {
          "index": {
            "type": "integer",
            "description": "Zero-based position of the row in the request.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "The row's item number, as sent.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "The row's warehouse code, as sent.",
            "nullable": true
          },
          "outcome": {
            "type": "string",
            "description": "`updated` or `failed`.",
            "nullable": true
          },
          "error": {
            "$ref": "#/components/schemas/BatchPatchItemWarehousesRowError"
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertItemsItemRow": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "pattern": "^[A-Z0-9\\-_]+$",
            "type": "string",
            "description": "Business key. Required — it identifies the row in the response."
          },
          "name": {
            "maxLength": 200,
            "type": "string",
            "description": "Item name. Required when the item does not exist yet.",
            "nullable": true
          },
          "description": {
            "maxLength": 2000,
            "type": "string",
            "description": "Long-form description.",
            "nullable": true
          },
          "barcode": {
            "maxLength": 50,
            "type": "string",
            "description": "EAN / GTIN barcode.",
            "nullable": true
          },
          "costPrice": {
            "type": "number",
            "description": "Purchase / cost price in the tenant default currency.",
            "format": "double",
            "nullable": true
          },
          "salesPrice": {
            "type": "number",
            "description": "Default sales price in the tenant default currency.",
            "format": "double",
            "nullable": true
          },
          "netWeight": {
            "type": "number",
            "description": "Net weight in kilograms.",
            "format": "double",
            "nullable": true
          },
          "width": {
            "type": "number",
            "description": "Width in centimetres.",
            "format": "double",
            "nullable": true
          },
          "height": {
            "type": "number",
            "description": "Height in centimetres.",
            "format": "double",
            "nullable": true
          },
          "depth": {
            "type": "number",
            "description": "Depth in centimetres.",
            "format": "double",
            "nullable": true
          },
          "hsCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Harmonized System (HS / KN) customs tariff code.",
            "nullable": true
          },
          "countryOfOrigin": {
            "pattern": "^[A-Z]{2}$",
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country of manufacture.",
            "nullable": true
          },
          "categoryCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the item category to file the item under. The category must already exist —\ncreate it with POST /preview/categories first.",
            "nullable": true
          },
          "brandCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the brand. The brand must already exist — create it with POST /preview/brands first.",
            "nullable": true
          },
          "unitCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Code of the base unit of measure, for example `ST` or `KG`.",
            "nullable": true
          },
          "itemType": {
            "$ref": "#/components/schemas/PublicItemType"
          },
          "status": {
            "$ref": "#/components/schemas/PublicItemStatus"
          },
          "variantAxes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "On a `VariantMaster`: the names of the variant attributes it varies along, e.g.\n`[\"Material\", \"Finish\"]`. The attributes must exist; an axis already on the item is left alone.",
            "nullable": true
          },
          "parentItemNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "On a variant: the item number of its `VariantMaster`. The master must exist — a row\nearlier in the same batch is enough.",
            "nullable": true
          },
          "variantValues": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "On a variant: its value per axis, attribute name → value, e.g.\n`{\"Material\": \"Solid oak\", \"Finish\": \"Oak oiled\"}`. One value for every axis the master\ncarries. A value missing under an existing attribute is created.",
            "nullable": true
          },
          "packages": {
            "maxItems": 99,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchUpsertItemsPackageRow"
            },
            "description": "The parcels one base unit ships in, in parcel-number order — e.g. a sofa shipped as frame\nand cushions. Omit to leave the item's parcels alone; a list replaces them, and an empty\nlist removes them. Each parcel's barcode must not already identify another item, unit or parcel.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertItemsPackageRow": {
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 100,
            "type": "string",
            "description": "What the parcel holds, e.g. `Frame`.",
            "nullable": true
          },
          "length": {
            "type": "number",
            "description": "Length in cm.",
            "format": "double",
            "nullable": true
          },
          "width": {
            "type": "number",
            "description": "Width in cm.",
            "format": "double",
            "nullable": true
          },
          "height": {
            "type": "number",
            "description": "Height in cm.",
            "format": "double",
            "nullable": true
          },
          "grossWeight": {
            "type": "number",
            "description": "Gross weight in kg, including packaging.",
            "format": "double",
            "nullable": true
          },
          "barcode": {
            "maxLength": 50,
            "type": "string",
            "description": "The parcel's own barcode (EAN).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertItemsRequest": {
        "required": [
          "items"
        ],
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchUpsertItemsItemRow"
            },
            "description": "The rows to load. At most 200 per call."
          },
          "mode": {
            "enum": [
              "Upsert",
              "Create",
              "Update"
            ],
            "type": "string",
            "description": "`upsert` (default) creates missing items and updates existing ones, `create`\n            fails a row whose item number already exists, `update` fails a row whose item number\n            does not exist."
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertItemsResponse": {
        "type": "object",
        "properties": {
          "createdCount": {
            "type": "integer",
            "format": "int32"
          },
          "updatedCount": {
            "type": "integer",
            "format": "int32"
          },
          "failedCount": {
            "type": "integer",
            "format": "int32"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchUpsertItemsRowResult"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertItemsRowError": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertItemsRowResult": {
        "type": "object",
        "properties": {
          "index": {
            "type": "integer",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "nullable": true
          },
          "outcome": {
            "type": "string",
            "description": "`created`, `updated` or `failed`.",
            "nullable": true
          },
          "error": {
            "$ref": "#/components/schemas/BatchUpsertItemsRowError"
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertPriceListLinesLineRow": {
        "required": [
          "itemNumber",
          "unitPrice"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Item number of the item to price. Part of the line's key."
          },
          "unitPrice": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "The fixed price, in the price list's currency. Serialised as a decimal string.",
            "format": "double"
          },
          "minQuantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "The price applies from this quantity. Omit for the first unit. Part of the key.",
            "format": "double",
            "nullable": true
          },
          "maxQuantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "Upper quantity limit. Omit for none; an existing limit is removed.",
            "format": "double",
            "nullable": true
          },
          "validFrom": {
            "type": "string",
            "description": "First day the price applies. Omit for no start date. Part of the key.",
            "format": "date",
            "nullable": true
          },
          "validTo": {
            "type": "string",
            "description": "Last day the price applies. Omit for none; an existing end date is removed.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertPriceListLinesRequest": {
        "required": [
          "lines"
        ],
        "type": "object",
        "properties": {
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchUpsertPriceListLinesLineRow"
            },
            "description": "The prices to set. At most 500 per call."
          },
          "mode": {
            "enum": [
              "Upsert",
              "Create",
              "Update"
            ],
            "type": "string",
            "description": "`upsert` (default) creates missing lines and updates existing ones, `create` fails\n            a row whose line already exists, `update` fails a row whose line does not exist."
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertPriceListLinesResponse": {
        "type": "object",
        "properties": {
          "createdCount": {
            "type": "integer",
            "format": "int32"
          },
          "updatedCount": {
            "type": "integer",
            "format": "int32"
          },
          "failedCount": {
            "type": "integer",
            "format": "int32"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchUpsertPriceListLinesRowResult"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertPriceListLinesRowError": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchUpsertPriceListLinesRowResult": {
        "type": "object",
        "properties": {
          "index": {
            "type": "integer",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "nullable": true
          },
          "outcome": {
            "type": "string",
            "description": "`created`, `updated` or `failed`.",
            "nullable": true
          },
          "error": {
            "$ref": "#/components/schemas/BatchUpsertPriceListLinesRowError"
          }
        },
        "additionalProperties": false
      },
      "BatchesBlockBatchRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchesPublicBatchDelivery": {
        "type": "object",
        "properties": {
          "salesOrderNumber": {
            "type": "string",
            "nullable": true
          },
          "customerNumber": {
            "type": "string",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "format": "double"
          },
          "shippedDate": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "BatchesPublicBatchResponse": {
        "type": "object",
        "properties": {
          "batchNumber": {
            "type": "string",
            "nullable": true
          },
          "itemNumber": {
            "type": "string",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "isPickable": {
            "type": "boolean"
          },
          "expiryDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "bestBeforeDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "receivedDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "daysUntilExpiry": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "quantityOnHand": {
            "type": "number",
            "format": "double"
          },
          "supplierName": {
            "type": "string",
            "nullable": true
          },
          "supplierBatchNumber": {
            "type": "string",
            "nullable": true
          },
          "isRecalled": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "BatchesPublicBatchTraceResponse": {
        "type": "object",
        "properties": {
          "batchNumber": {
            "type": "string",
            "nullable": true
          },
          "itemNumber": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "quantityReceived": {
            "type": "number",
            "format": "double"
          },
          "quantityDelivered": {
            "type": "number",
            "format": "double"
          },
          "quantityOnHand": {
            "type": "number",
            "format": "double"
          },
          "supplierName": {
            "type": "string",
            "nullable": true
          },
          "supplierBatchNumber": {
            "type": "string",
            "nullable": true
          },
          "purchaseOrderNumber": {
            "type": "string",
            "nullable": true
          },
          "workOrderNumber": {
            "type": "string",
            "nullable": true
          },
          "deliveredTo": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchesPublicBatchDelivery"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BookShipmentResponse": {
        "type": "object",
        "properties": {
          "trackingNumber": {
            "type": "string",
            "description": "Carrier tracking number, if the carrier returned one.",
            "nullable": true
          },
          "externalBookingId": {
            "type": "string",
            "description": "The carrier's own booking reference.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CalculateConfigurationRequest": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Item number of the configurable product."
          },
          "quantity": {
            "type": "number",
            "description": "How many units to price. Must be greater than zero.",
            "format": "double"
          },
          "values": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationValueInput"
            },
            "description": "The chosen values. Omit or leave empty to price the item with no choices made.",
            "nullable": true
          },
          "customerNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Customer to price for. Applies their price lists, agreements and currency. Omit for the default price.",
            "nullable": true
          },
          "currencyCode": {
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency to price in. Defaults to the customer's currency, then the tenant base currency.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CancelTicketRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "maxLength": 1000,
            "type": "string",
            "description": "Why the ticket is cancelled. Stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CloseTicketRequest": {
        "type": "object",
        "properties": {
          "note": {
            "maxLength": 1000,
            "type": "string",
            "description": "Closing note stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ConfirmPurchaseOrderRequest": {
        "type": "object",
        "properties": {
          "supplierReference": {
            "maxLength": 100,
            "type": "string",
            "description": "The supplier's own order or confirmation number, if they quoted one.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateBrandRequest": {
        "required": [
          "code",
          "name"
        ],
        "type": "object",
        "properties": {
          "code": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Business key. Item rows reference this, so pick something stable."
          },
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Display name."
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "Longer description, e.g. for a brand page in the web shop.",
            "nullable": true
          },
          "logoUrl": {
            "maxLength": 500,
            "type": "string",
            "description": "Absolute URL to the brand logo.",
            "format": "uri",
            "nullable": true
          },
          "websiteUrl": {
            "maxLength": 500,
            "type": "string",
            "description": "Absolute URL to the brand's own site.",
            "format": "uri",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order in brand listings.",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "CreateCategoryRequest": {
        "required": [
          "code",
          "name"
        ],
        "type": "object",
        "properties": {
          "code": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Business key. Item rows reference this, so pick something stable."
          },
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Display name."
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "Longer description, e.g. for a web shop category page.",
            "nullable": true
          },
          "parentCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of an existing category to nest this one under. Omit for a root category. Load a tree\nparents-first — a code that does not exist yet is rejected with 400.",
            "nullable": true
          },
          "slug": {
            "maxLength": 200,
            "type": "string",
            "description": "URL segment for the web shop. Defaults to the code.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order among its siblings.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateConfigurationRequest": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Item number of the configurable product."
          },
          "quantity": {
            "type": "number",
            "description": "How many units of the configured product. Must be greater than zero.",
            "format": "double"
          },
          "values": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationValueInput"
            },
            "description": "The chosen values.",
            "nullable": true
          },
          "customerNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Customer the configuration is for. Required before it can be turned into an order, but may be filled in later with a reconfigure.",
            "nullable": true
          },
          "title": {
            "maxLength": 200,
            "type": "string",
            "description": "Free-text title. Defaults to the item name.",
            "nullable": true
          },
          "description": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text description, e.g. which room or window the product is for.",
            "nullable": true
          },
          "warehouseCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Warehouse to plan the configuration against. Optional and left unset when omitted — the warehouse is then resolved (customer's, then the tenant default) when the configuration becomes an order.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateContentPageRequest": {
        "required": [
          "slug",
          "title"
        ],
        "type": "object",
        "properties": {
          "slug": {
            "maxLength": 100,
            "minLength": 1,
            "pattern": "^[a-z0-9-]+$",
            "type": "string",
            "description": "URL slug, unique within the channel. Lowercase letters, digits and hyphens."
          },
          "title": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Page title. Required."
          },
          "pageType": {
            "$ref": "#/components/schemas/PublicContentPageType"
          },
          "metaDescription": {
            "maxLength": 500,
            "type": "string",
            "description": "SEO meta description.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order in listings and navigation.",
            "format": "int32"
          },
          "parentSlug": {
            "maxLength": 100,
            "type": "string",
            "description": "Slug of the parent page, for a hierarchy.",
            "nullable": true
          },
          "excerpt": {
            "maxLength": 1000,
            "type": "string",
            "description": "Short summary for list cards and RSS. Articles.",
            "nullable": true
          },
          "featuredImageUrl": {
            "maxLength": 1000,
            "type": "string",
            "description": "Cover image for list cards and Open Graph. Articles.",
            "nullable": true
          },
          "authorName": {
            "maxLength": 200,
            "type": "string",
            "description": "Displayed author. Free text.",
            "nullable": true
          },
          "publishDate": {
            "type": "string",
            "description": "Editorial publication date. May be in the future to schedule.",
            "format": "date-time",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tags for filtering and related articles.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateCustomerRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Full company or person name."
          },
          "customerNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Unique customer number. Auto-generated from the tenant number sequence if omitted.",
            "nullable": true
          },
          "organizationNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Company registration number / org.nr, e.g. `5560001234`.",
            "nullable": true
          },
          "vatNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "VAT registration number, e.g. `SE556000123401`.",
            "nullable": true
          },
          "invoiceEmail": {
            "maxLength": 200,
            "type": "string",
            "description": "Email address for invoices and order confirmations.",
            "format": "email",
            "nullable": true
          },
          "phone": {
            "maxLength": 50,
            "type": "string",
            "description": "Primary phone number.",
            "nullable": true
          },
          "street1": {
            "maxLength": 200,
            "type": "string",
            "description": "Street address line 1.",
            "nullable": true
          },
          "street2": {
            "maxLength": 200,
            "type": "string",
            "description": "Street address line 2 — suite, c/o, etc.",
            "nullable": true
          },
          "postalCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Postal / ZIP code.",
            "nullable": true
          },
          "city": {
            "maxLength": 100,
            "type": "string",
            "description": "City name.",
            "nullable": true
          },
          "countryCode": {
            "maxLength": 2,
            "pattern": "^[A-Z]{2}$",
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`, `DE`, `NO`.",
            "nullable": true
          },
          "defaultCurrencyCode": {
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency code, e.g. `SEK`, `EUR`. If omitted, the tenant default is used.",
            "nullable": true
          },
          "notes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text internal notes (not visible to the customer).",
            "nullable": true
          },
          "defaultBackorderBehavior": {
            "$ref": "#/components/schemas/BackorderBehavior"
          }
        },
        "additionalProperties": false
      },
      "CreateInventoryAdjustmentRequest": {
        "required": [
          "itemNumber",
          "locationCode",
          "quantity",
          "warehouseCode"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Item to adjust."
          },
          "warehouseCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Warehouse the stock sits in."
          },
          "locationCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Location within the warehouse."
          },
          "quantity": {
            "type": "number",
            "description": "Signed change. Positive increases stock, negative decreases it. This is a delta, not the\nnew balance — pass -3 to write off three units.",
            "format": "double"
          },
          "transactionType": {
            "enum": [
              "Receipt",
              "Issue",
              "Adjustment",
              "Transfer",
              "Return",
              "Scrap",
              "ConsignmentConsumption",
              "Revaluation"
            ],
            "type": "string",
            "description": "How to classify the movement: Adjustment (default) or Scrap. Receipt, Issue and Transfer\nare produced by their own flows and are rejected here; Return belongs to the return flow."
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Reason for the adjustment. Recommended — this is the audit trail.",
            "nullable": true
          },
          "batchNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Batch (lot) the movement applies to. Required when the item is batch tracked in this\nwarehouse; the batch must already exist. Omitting it on a tracked item returns 400.",
            "nullable": true
          },
          "serialNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Serial number the movement applies to. Required when the item is serial tracked.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateInventoryCountRequest": {
        "required": [
          "type",
          "warehouseCode"
        ],
        "type": "object",
        "properties": {
          "warehouseCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Warehouse to count."
          },
          "type": {
            "$ref": "#/components/schemas/InventoryCountType"
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text description of the count.",
            "nullable": true
          },
          "zoneFilter": {
            "maxLength": 50,
            "type": "string",
            "description": "Zone to limit the count to. Used with type Location.",
            "nullable": true
          },
          "locationCodeFilter": {
            "maxLength": 50,
            "type": "string",
            "description": "Location code prefix to limit the count to. Used with type Location.",
            "nullable": true
          },
          "categoryCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Item category to count. Required for type Category.",
            "nullable": true
          },
          "randomSampleSize": {
            "maximum": 10000,
            "minimum": 1,
            "type": "integer",
            "description": "Number of locations to sample. Required for type Random.",
            "format": "int32",
            "nullable": true
          },
          "itemNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Item to count. Required for type Impulse.",
            "nullable": true
          },
          "blindCount": {
            "type": "boolean",
            "description": "Hide the recorded quantity from the counter. Default true."
          },
          "autoStart": {
            "type": "boolean",
            "description": "Move straight to InProgress instead of Draft. Default false."
          }
        },
        "additionalProperties": false
      },
      "CreateInventoryMovementRequest": {
        "required": [
          "fromLocationCode",
          "itemNumber",
          "quantity",
          "toLocationCode",
          "warehouseCode"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Item to move."
          },
          "warehouseCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Warehouse the move happens in. Both locations must belong to it."
          },
          "fromLocationCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Location to move stock out of."
          },
          "toLocationCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Location to move stock into."
          },
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Quantity to move. Must be greater than zero.",
            "format": "double"
          },
          "moveAllocations": {
            "type": "boolean",
            "description": "Allow hard-allocated stock to be moved. Free stock moves first; allocations follow only\nfor the quantity that exceeds it, so the source keeps its allocations wherever possible.\nDefault false, which rejects a move larger than the free quantity."
          },
          "serialNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Serial number, for serial-tracked items.",
            "nullable": true
          },
          "batchNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Batch / lot number, for batch-tracked items.",
            "nullable": true
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text notes stored on the movement.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateInventoryMovementResponse": {
        "type": "object",
        "properties": {
          "quantityMoved": {
            "type": "number",
            "description": "Quantity that was moved. Serialised as a decimal string.",
            "format": "double"
          },
          "fromLocationBalance": {
            "type": "number",
            "description": "On-hand quantity left at the source location.",
            "format": "double"
          },
          "toLocationBalance": {
            "type": "number",
            "description": "On-hand quantity at the destination location after the move.",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "CreateItemChannelRequest": {
        "required": [
          "channelCode"
        ],
        "type": "object",
        "properties": {
          "channelCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Code of the channel to publish on. Required."
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the publication is live. Defaults to true."
          },
          "name": {
            "maxLength": 200,
            "type": "string",
            "description": "Channel-specific name. Omit to use the item's own.",
            "nullable": true
          },
          "description": {
            "maxLength": 4000,
            "type": "string",
            "description": "Channel-specific long description. Omit to use the item's own.",
            "nullable": true
          },
          "shortDescription": {
            "maxLength": 500,
            "type": "string",
            "description": "Channel-specific short description. Omit to use the item's own.",
            "nullable": true
          },
          "metaTitle": {
            "maxLength": 100,
            "type": "string",
            "description": "SEO meta title for this channel.",
            "nullable": true
          },
          "metaDescription": {
            "maxLength": 300,
            "type": "string",
            "description": "SEO meta description for this channel.",
            "nullable": true
          },
          "slug": {
            "maxLength": 200,
            "pattern": "^[a-z0-9-]+$",
            "type": "string",
            "description": "URL slug in this channel. Generated from the name if omitted.",
            "nullable": true
          },
          "showStock": {
            "type": "boolean",
            "description": "Whether stock is shown for this item here. Defaults to true."
          },
          "stockDisplayMode": {
            "$ref": "#/components/schemas/PublicStockDisplayMode"
          },
          "allowBackorder": {
            "type": "boolean",
            "description": "Backorder override. Omit to inherit from the item, then the channel.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order within the channel. Defaults to 0.",
            "format": "int32"
          },
          "isFeatured": {
            "type": "boolean",
            "description": "Whether the item is featured here. Defaults to false."
          },
          "publishDate": {
            "type": "string",
            "description": "When the item becomes visible. Omit to publish immediately.",
            "format": "date-time",
            "nullable": true
          },
          "unpublishDate": {
            "type": "string",
            "description": "When the item stops being visible. Omit for never.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateItemRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Display name / product name."
          },
          "itemNumber": {
            "maxLength": 50,
            "pattern": "^[A-Z0-9\\-_]+$",
            "type": "string",
            "description": "Unique item number. Only uppercase letters, digits, hyphens and underscores are allowed. Auto-generated if omitted.",
            "nullable": true
          },
          "description": {
            "maxLength": 2000,
            "type": "string",
            "description": "Long-form description, e.g. for a webshop product page.",
            "nullable": true
          },
          "barcode": {
            "maxLength": 50,
            "type": "string",
            "description": "EAN / GTIN barcode or other scanning code.",
            "nullable": true
          },
          "costPrice": {
            "type": "number",
            "description": "Purchase / cost price in the tenant default currency.",
            "format": "double",
            "nullable": true
          },
          "salesPrice": {
            "type": "number",
            "description": "Default sales price in the tenant default currency.",
            "format": "double",
            "nullable": true
          },
          "netWeight": {
            "type": "number",
            "description": "Net weight in kilograms.",
            "format": "double",
            "nullable": true
          },
          "hsCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Harmonized System (HS / KN) customs tariff code.",
            "nullable": true
          },
          "countryOfOrigin": {
            "pattern": "^[A-Z]{2}$",
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country of manufacture, e.g. `SE`, `CN`.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateOrderDeliveryAddressInput": {
        "required": [
          "city",
          "countryCode",
          "name",
          "postalCode",
          "street1"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "Recipient name or company name."
          },
          "street1": {
            "minLength": 1,
            "type": "string",
            "description": "Street address line 1."
          },
          "postalCode": {
            "minLength": 1,
            "type": "string",
            "description": "Postal code."
          },
          "city": {
            "minLength": 1,
            "type": "string",
            "description": "City."
          },
          "countryCode": {
            "minLength": 1,
            "pattern": "^[A-Z]{2}$",
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`."
          },
          "street2": {
            "type": "string",
            "description": "Street address line 2 — c/o, suite, etc.",
            "nullable": true
          },
          "contactPerson": {
            "type": "string",
            "description": "Contact person at the delivery address.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Phone number at the delivery address.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address at the delivery address.",
            "format": "email",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateOrderFromConfigurationRequest": {
        "type": "object",
        "properties": {
          "requestedDeliveryDate": {
            "type": "string",
            "description": "Delivery date to request on the order. Omit to leave it open.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateOrderLineInput": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "minLength": 1,
            "type": "string",
            "description": "Item number of an existing item."
          },
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Ordered quantity. Must be greater than zero.",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Overrides the item's default sales price.",
            "format": "double",
            "nullable": true
          },
          "discountPercent": {
            "maximum": 100,
            "minimum": 0,
            "type": "number",
            "description": "Line discount in percent (0–100).",
            "format": "double",
            "nullable": true
          },
          "unit": {
            "maxLength": 20,
            "type": "string",
            "description": "Unit of measure code, e.g. `st`, `kg`. Defaults to the item's base unit.",
            "nullable": true
          },
          "requestedDeliveryDate": {
            "type": "string",
            "description": "Line-level requested delivery date (overrides the order-level date).",
            "format": "date",
            "nullable": true
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text line notes.",
            "nullable": true
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Customer-facing line text. Defaults to the item name when omitted.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateOrderRequest": {
        "required": [
          "customerNumber"
        ],
        "type": "object",
        "properties": {
          "customerNumber": {
            "minLength": 1,
            "type": "string",
            "description": "Number of an existing customer (exact match)."
          },
          "orderDate": {
            "type": "string",
            "description": "Order date. Defaults to today if omitted.",
            "format": "date",
            "nullable": true
          },
          "requestedDeliveryDate": {
            "type": "string",
            "description": "Requested delivery date from the customer.",
            "format": "date",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code, e.g. `SEK`, `EUR`. Defaults to the customer's currency.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Code of the warehouse to fulfil from. Defaults to the tenant's default warehouse.",
            "nullable": true
          },
          "orderTypeCode": {
            "type": "string",
            "description": "Order type code. Defaults to the tenant default.",
            "nullable": true
          },
          "paymentTermCode": {
            "type": "string",
            "description": "Payment term code — overrides the customer default.",
            "nullable": true
          },
          "deliveryTermCode": {
            "type": "string",
            "description": "Delivery term / Incoterm code — overrides the customer default.",
            "nullable": true
          },
          "shippingMethodCode": {
            "type": "string",
            "description": "Shipping method / carrier code — overrides the customer default.",
            "nullable": true
          },
          "deliveryAddress": {
            "$ref": "#/components/schemas/CreateOrderDeliveryAddressInput"
          },
          "customerContactId": {
            "type": "string",
            "description": "ID of the customer contact person.",
            "format": "uuid",
            "nullable": true
          },
          "backorderBehavior": {
            "$ref": "#/components/schemas/BackorderBehavior"
          },
          "customerReference": {
            "maxLength": 100,
            "type": "string",
            "description": "Customer's own reference / purchase order number.",
            "nullable": true
          },
          "externalNotes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text notes printed on order documents.",
            "nullable": true
          },
          "orderNumber": {
            "type": "string",
            "description": "Custom order number. Auto-generated if omitted. Returns 409 if already in use.",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateOrderLineInput"
            },
            "description": "Optional order lines to create atomically with the order.",
            "nullable": true
          },
          "createAsDraft": {
            "type": "boolean",
            "description": "Set to `true` to keep the order in Draft status — useful when adding more lines via POST /orders/{orderNumber}/lines before placing."
          }
        },
        "additionalProperties": false
      },
      "CreatePurchaseOrderLineInput": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "minLength": 1,
            "type": "string",
            "description": "Item number of an existing item."
          },
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Ordered quantity. Must be greater than zero.",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Overrides the supplier's price for the item. Omit to use the supplier price list.",
            "format": "double",
            "nullable": true
          },
          "unit": {
            "maxLength": 20,
            "type": "string",
            "description": "Unit of measure code, e.g. `st`, `kg`. Defaults to the item's base unit.",
            "nullable": true
          },
          "expectedDate": {
            "type": "string",
            "description": "Expected delivery date for this line (overrides the order-level date).",
            "format": "date",
            "nullable": true
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text line notes.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreatePurchaseOrderRequest": {
        "required": [
          "supplierNumber"
        ],
        "type": "object",
        "properties": {
          "supplierNumber": {
            "minLength": 1,
            "type": "string",
            "description": "Number of an existing supplier (exact match)."
          },
          "orderDate": {
            "type": "string",
            "description": "Order date. Defaults to today if omitted.",
            "format": "date",
            "nullable": true
          },
          "expectedDeliveryDate": {
            "type": "string",
            "description": "Date the goods are expected to arrive. Calculated from the supplier lead time if omitted.",
            "format": "date",
            "nullable": true
          },
          "warehouseCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the warehouse to receive into. Defaults to the tenant's default warehouse.",
            "nullable": true
          },
          "currencyCode": {
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency code, e.g. `SEK`, `EUR`. Defaults to the supplier's currency.",
            "nullable": true
          },
          "paymentTermCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Payment term code — overrides the supplier default.",
            "nullable": true
          },
          "deliveryTermCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Delivery term / Incoterm code — overrides the supplier default.",
            "nullable": true
          },
          "shippingMethodCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Shipping method / carrier code — overrides the supplier default.",
            "nullable": true
          },
          "supplierReference": {
            "maxLength": 100,
            "type": "string",
            "description": "Our reference at the supplier, or the supplier's own order number.",
            "nullable": true
          },
          "externalNotes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text notes printed on the purchase order document.",
            "nullable": true
          },
          "orderNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Custom order number. Auto-generated if omitted. Returns 409 if already in use.",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreatePurchaseOrderLineInput"
            },
            "description": "Purchase order lines to create atomically with the order.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateQuoteLineInput": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Item number of an existing item. Required: a quote line without an item cannot be carried\ninto a sales order, so the API does not accept one."
          },
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Quantity. Must be greater than zero.",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Net unit price in the quote currency.",
            "format": "double"
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Line text shown to the customer. Defaults to the item's name.",
            "nullable": true
          },
          "unit": {
            "maxLength": 20,
            "type": "string",
            "description": "Unit of measure code, e.g. `st`.",
            "nullable": true
          },
          "discountPercent": {
            "maximum": 100,
            "minimum": 0,
            "type": "number",
            "description": "Line discount in percent (0–100).",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateQuoteRequest": {
        "required": [
          "customerNumber"
        ],
        "type": "object",
        "properties": {
          "customerNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Number of an existing customer."
          },
          "title": {
            "maxLength": 200,
            "type": "string",
            "description": "Short title shown on the quote.",
            "nullable": true
          },
          "description": {
            "maxLength": 4000,
            "type": "string",
            "description": "Longer description shown on the quote.",
            "nullable": true
          },
          "currencyCode": {
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency code. Defaults to the customer's currency.",
            "nullable": true
          },
          "quoteDate": {
            "type": "string",
            "description": "Quote date. Defaults to today.",
            "format": "date",
            "nullable": true
          },
          "validUntil": {
            "type": "string",
            "description": "Last date the quote is valid. Defaults to the tenant's quote validity setting.",
            "format": "date",
            "nullable": true
          },
          "customerContactId": {
            "type": "string",
            "description": "ID of the customer contact person the quote is addressed to.",
            "format": "uuid",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateQuoteLineInput"
            },
            "description": "Quote lines to create atomically with the quote.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateRedirectRequest": {
        "required": [
          "fromPath",
          "toPath"
        ],
        "type": "object",
        "properties": {
          "fromPath": {
            "maxLength": 400,
            "minLength": 1,
            "type": "string",
            "description": "The old path to redirect, e.g. `/old-product`. Normalized to lowercase with a leading\nslash and no trailing slash. Must be unique within the channel."
          },
          "toPath": {
            "maxLength": 2000,
            "minLength": 1,
            "type": "string",
            "description": "Where to send the visitor: a path starting with `/` or an absolute http(s) URL."
          },
          "statusCode": {
            "type": "integer",
            "description": "301 (permanent, the default) or 302 (temporary).",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateReturnLineInput": {
        "type": "object",
        "properties": {
          "orderLineNumber": {
            "type": "integer",
            "description": "Line number on the sales order being returned.",
            "format": "int32"
          },
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Quantity returned. Must be greater than zero.",
            "format": "double"
          },
          "condition": {
            "$ref": "#/components/schemas/ReturnLineCondition"
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text notes on the line.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateReturnRequest": {
        "required": [
          "orderNumber",
          "reason"
        ],
        "type": "object",
        "properties": {
          "orderNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Sales order the goods are returned from."
          },
          "reason": {
            "$ref": "#/components/schemas/ReturnReason"
          },
          "warehouseCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Warehouse to receive the goods into. Defaults to the order's warehouse.",
            "nullable": true
          },
          "returnDate": {
            "type": "string",
            "description": "Date the return was registered. Defaults to today.",
            "format": "date",
            "nullable": true
          },
          "rmaNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "The customer's own RMA reference.",
            "nullable": true
          },
          "externalNotes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Notes visible to the customer.",
            "nullable": true
          },
          "internalNotes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Notes visible only internally.",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateReturnLineInput"
            },
            "description": "Lines to return. Omit to return the whole order — every delivered line is added at its\ndelivered quantity.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateShipmentRequest": {
        "required": [
          "orderNumbers"
        ],
        "type": "object",
        "properties": {
          "orderNumbers": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Sales orders to fulfil. Pass more than one to consolidate them into a single shipment —\nthey must share a delivery address and shipping method for consolidation to be accepted."
          },
          "shippingMethodCode": {
            "type": "string",
            "description": "Shipping method / carrier code. Defaults to the order's shipping method.",
            "nullable": true
          },
          "notes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text notes on the shipment.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateSupplierRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Full company name."
          },
          "supplierNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Custom supplier number. Auto-generated from the tenant number sequence if omitted.",
            "nullable": true
          },
          "currencyCode": {
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency code purchase orders are placed in, e.g. `SEK`, `EUR`. Defaults to the tenant base currency.",
            "nullable": true
          },
          "organizationNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Company registration number / org.nr.",
            "nullable": true
          },
          "vatNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "EU VAT registration number, e.g. `SE556012345601`. Validated against the EU VIES register in the background.",
            "nullable": true
          },
          "contactPerson": {
            "maxLength": 200,
            "type": "string",
            "description": "Primary contact person at the supplier.",
            "nullable": true
          },
          "purchaseOrderEmail": {
            "maxLength": 200,
            "type": "string",
            "description": "Email address purchase orders are sent to.",
            "format": "email",
            "nullable": true
          },
          "phone": {
            "maxLength": 50,
            "type": "string",
            "description": "Primary phone number.",
            "nullable": true
          },
          "street1": {
            "maxLength": 200,
            "type": "string",
            "description": "Street address line 1.",
            "nullable": true
          },
          "street2": {
            "maxLength": 200,
            "type": "string",
            "description": "Street address line 2 — c/o, suite, etc.",
            "nullable": true
          },
          "postalCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Postal / ZIP code.",
            "nullable": true
          },
          "city": {
            "maxLength": 100,
            "type": "string",
            "description": "City name.",
            "nullable": true
          },
          "countryCode": {
            "maxLength": 2,
            "pattern": "^[A-Z]{2}$",
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`, `DE`.",
            "nullable": true
          },
          "paymentTermCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Payment term code — see GET /preview/reference/payment-terms.",
            "nullable": true
          },
          "deliveryTermCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Delivery term / Incoterm code — see GET /preview/reference/delivery-terms.",
            "nullable": true
          },
          "leadTimeDays": {
            "maximum": 3650,
            "minimum": 0,
            "type": "integer",
            "description": "Default lead time in calendar days from order to delivery.",
            "format": "int32",
            "nullable": true
          },
          "notes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text internal notes (not visible to the supplier).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateTicketRequest": {
        "required": [
          "description",
          "title"
        ],
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Short summary of the issue. Becomes the ticket's subject line."
          },
          "description": {
            "maxLength": 4000,
            "minLength": 1,
            "type": "string",
            "description": "The full message from the reporter."
          },
          "type": {
            "$ref": "#/components/schemas/PublicTicketSubmissionType"
          },
          "customerNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Customer the ticket belongs to. Omit when the reporter is not a known customer.",
            "nullable": true
          },
          "contactName": {
            "maxLength": 200,
            "type": "string",
            "description": "Name of the person reporting the issue.",
            "nullable": true
          },
          "contactEmail": {
            "maxLength": 200,
            "type": "string",
            "description": "Email address for replies. Strongly recommended — without it the reporter gets no confirmation and no answer.",
            "format": "email",
            "nullable": true
          },
          "contactPhone": {
            "maxLength": 50,
            "type": "string",
            "description": "Phone number of the person reporting the issue.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateTransferOrderLineInput": {
        "required": [
          "itemNumber"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Item to transfer."
          },
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Quantity to transfer. Must be greater than zero.",
            "format": "double"
          },
          "fromLocationCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Source location. Defaults to the source warehouse's pick logic.",
            "nullable": true
          },
          "toLocationCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Destination location. Defaults to the destination warehouse's receiving location.",
            "nullable": true
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text notes on the line.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateTransferOrderRequest": {
        "required": [
          "fromWarehouseCode",
          "toWarehouseCode"
        ],
        "type": "object",
        "properties": {
          "fromWarehouseCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Warehouse the stock leaves."
          },
          "toWarehouseCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Warehouse the stock arrives at. Must differ from the source."
          },
          "requestedDate": {
            "type": "string",
            "description": "Requested arrival date.",
            "format": "date",
            "nullable": true
          },
          "shippingMethodCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Shipping method / carrier code.",
            "nullable": true
          },
          "notes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text notes on the transfer.",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateTransferOrderLineInput"
            },
            "description": "Lines to create atomically with the transfer.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DeclineQuoteRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "maxLength": 1000,
            "type": "string",
            "description": "Why the customer declined. Feeds win/loss reporting.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "HoldTicketRequest": {
        "type": "object",
        "properties": {
          "note": {
            "maxLength": 1000,
            "type": "string",
            "description": "Why the ticket is paused. Stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "InventoryCountType": {
        "enum": [
          "Full",
          "Location",
          "Category",
          "ABC",
          "Random",
          "Impulse",
          "Opening"
        ],
        "type": "string"
      },
      "JsonNode": {
        "type": "object",
        "properties": {
          "options": {
            "$ref": "#/components/schemas/JsonNodeOptions"
          },
          "parent": {
            "$ref": "#/components/schemas/JsonNode"
          },
          "root": {
            "$ref": "#/components/schemas/JsonNode"
          }
        },
        "additionalProperties": false
      },
      "JsonNodeOptions": {
        "type": "object",
        "properties": {
          "propertyNameCaseInsensitive": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "MigrateTicketMessageRequest": {
        "required": [
          "content",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "content": {
            "maxLength": 8000,
            "minLength": 1,
            "type": "string",
            "description": "The message body."
          },
          "createdAt": {
            "type": "string",
            "description": "When the message was written in the source system.",
            "format": "date-time"
          },
          "authorName": {
            "maxLength": 200,
            "type": "string",
            "description": "Who wrote it. Shown next to the message in the thread.",
            "nullable": true
          },
          "isInternal": {
            "type": "boolean",
            "description": "Internal note, never shown to the reporter in the portal."
          }
        },
        "additionalProperties": false
      },
      "MigrateTicketRequest": {
        "required": [
          "createdAt",
          "externalReference",
          "title"
        ],
        "type": "object",
        "properties": {
          "externalReference": {
            "maxLength": 100,
            "minLength": 1,
            "type": "string",
            "description": "The ticket's identity in the system it comes from, prefixed with that system's name:\n`SuperOffice:112614`. Must be unique across tickets — it is what makes the migration\nresumable."
          },
          "title": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Ticket subject."
          },
          "createdAt": {
            "type": "string",
            "description": "When the ticket was created in the source system.",
            "format": "date-time"
          },
          "description": {
            "maxLength": 4000,
            "type": "string",
            "description": "Full description, normally the reporter's first message.",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/TicketType"
          },
          "status": {
            "$ref": "#/components/schemas/TicketStatus"
          },
          "priority": {
            "$ref": "#/components/schemas/TicketPriority"
          },
          "source": {
            "$ref": "#/components/schemas/TicketSource"
          },
          "sourceChannel": {
            "$ref": "#/components/schemas/SourceChannel"
          },
          "customerNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Customer the ticket belongs to. Omit when unknown.",
            "nullable": true
          },
          "contactName": {
            "maxLength": 200,
            "type": "string",
            "description": "Name of the person who reported the issue.",
            "nullable": true
          },
          "contactEmail": {
            "maxLength": 254,
            "type": "string",
            "description": "Email address of the reporter, as it stood in the source system.",
            "nullable": true
          },
          "contactPhone": {
            "maxLength": 50,
            "type": "string",
            "description": "Phone number of the reporter.",
            "nullable": true
          },
          "queueCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the queue the ticket should land in.",
            "nullable": true
          },
          "firstResponseAt": {
            "type": "string",
            "description": "When the first reply went out, if known.",
            "format": "date-time",
            "nullable": true
          },
          "resolvedAt": {
            "type": "string",
            "description": "When the ticket was resolved, if known.",
            "format": "date-time",
            "nullable": true
          },
          "closedAt": {
            "type": "string",
            "description": "When the ticket was closed, if known.",
            "format": "date-time",
            "nullable": true
          },
          "resolutionType": {
            "$ref": "#/components/schemas/TicketResolutionType"
          },
          "resolutionNotes": {
            "maxLength": 4000,
            "type": "string",
            "description": "Resolution description.",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tags to carry over, e.g. the category from the source system.",
            "nullable": true
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MigrateTicketMessageRequest"
            },
            "description": "The message thread, oldest first.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "MigrateTicketResponse": {
        "type": "object",
        "properties": {
          "ticketId": {
            "type": "string",
            "format": "uuid"
          },
          "ticketNumber": {
            "type": "string",
            "nullable": true
          },
          "alreadyExisted": {
            "type": "boolean"
          },
          "messageCount": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "PackShipmentRequest": {
        "type": "object",
        "properties": {
          "packageNumber": {
            "type": "string",
            "description": "Package to pack into. Optional when the shipment has exactly one package; required when it\nhas several, otherwise the call returns 409.",
            "nullable": true
          },
          "confirmWhenFullyPacked": {
            "type": "boolean",
            "description": "Confirm packing when everything picked was packed. Default true. Confirming books the\nshipment with the carrier when the shipping method is set up for automatic booking."
          }
        },
        "additionalProperties": false
      },
      "PackShipmentResponse": {
        "type": "object",
        "properties": {
          "packedCount": {
            "type": "integer",
            "description": "Number of lines packed by this call.",
            "format": "int32"
          },
          "packageNumber": {
            "type": "string",
            "description": "The package the quantities were packed into.",
            "nullable": true
          },
          "skipped": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PackShipmentSkippedLineResponse"
            },
            "description": "Lines that could not be packed automatically, with the reason.",
            "nullable": true
          },
          "confirmed": {
            "type": "boolean",
            "description": "Whether packing was confirmed. False when lines were skipped."
          },
          "status": {
            "$ref": "#/components/schemas/PublicShipmentStatus"
          }
        },
        "additionalProperties": false
      },
      "PackShipmentSkippedLineResponse": {
        "type": "object",
        "properties": {
          "orderLineNumber": {
            "type": "integer",
            "description": "Order line number of the line that was skipped.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number on the skipped line.",
            "nullable": true
          },
          "reason": {
            "type": "string",
            "description": "Why the line could not be packed automatically.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_BatchesPublicBatchResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchesPublicBatchResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicAttributeResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicAttributeResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicBrandResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicBrandResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicCategoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCategoryResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicChannelResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicChannelResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicConfigurationResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicContentPageResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicContentPageResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicCustomerAddressResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCustomerAddressResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicCustomerContactResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCustomerContactResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicCustomerResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCustomerResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicDeletionResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicDeletionResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicInventoryCountResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicInventoryCountResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicInventoryTransactionResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicInventoryTransactionResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicInvoiceResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicInvoiceResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicItemAssetResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemAssetResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicItemAvailabilityResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemAvailabilityResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicItemChannelResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemChannelResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicItemRelationResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemRelationResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicItemResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicItemVariantResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemVariantResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicItemWarehouseResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemWarehouseResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicMediaAssetResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicMediaAssetResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicOrderListItem": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicOrderListItem"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicPriceListLineResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPriceListLineResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicPriceListResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPriceListResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicPurchaseOrderLineResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPurchaseOrderLineResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicPurchaseOrderListItem": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPurchaseOrderListItem"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicQuoteLineResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicQuoteLineResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicQuoteResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicQuoteResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicReceiptLineResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReceiptLineResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicReceiptResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReceiptResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicRedirectResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicRedirectResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicReturnLineResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnLineResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicReturnResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicShipmentLineResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicShipmentLineResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicShipmentPackageResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicShipmentPackageResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicShipmentResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicShipmentResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicSupplierContactResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSupplierContactResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicSupplierItemResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSupplierItemResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicSupplierResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSupplierResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicTicketCommentResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicTicketCommentResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicTicketResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicTicketResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicTransferOrderLineResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicTransferOrderLineResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicTransferOrderResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicTransferOrderResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PagedResult_PublicWorkOrderResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicWorkOrderResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32",
            "readOnly": true
          },
          "hasPreviousPage": {
            "type": "boolean",
            "readOnly": true
          },
          "hasNextPage": {
            "type": "boolean",
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "PatchCategoryRequest": {
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "type": "string",
            "description": "Display name. Cannot be null.",
            "nullable": true
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "Longer description, e.g. for a web shop category page. Pass `null` to clear.",
            "nullable": true
          },
          "slug": {
            "maxLength": 200,
            "type": "string",
            "description": "URL segment for the web shop. Changing it records a 301 from the old address on every active\nchannel. Pass `null` to fall back to the code.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order among its siblings. Pass `null` to clear.",
            "format": "int32",
            "nullable": true
          },
          "metaTitle": {
            "maxLength": 200,
            "type": "string",
            "description": "Title of the category page in search results. Aim for 60 characters or fewer. Pass\n`null` to fall back to the name.",
            "nullable": true
          },
          "metaDescription": {
            "maxLength": 500,
            "type": "string",
            "description": "Description of the category page in search results. Aim for 155 characters or fewer.\nPass `null` to fall back to the description.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchContentPageRequest": {
        "type": "object",
        "properties": {
          "newSlug": {
            "maxLength": 100,
            "pattern": "^[a-z0-9-]+$",
            "type": "string",
            "description": "Move the page to a different slug. A 301 from the old URL is created automatically, so\nincoming links and their ranking survive.",
            "nullable": true
          },
          "title": {
            "maxLength": 200,
            "type": "string",
            "description": "Page title.",
            "nullable": true
          },
          "metaDescription": {
            "maxLength": 500,
            "type": "string",
            "description": "SEO meta description. Pass `null` to clear.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order in listings and navigation.",
            "format": "int32",
            "nullable": true
          },
          "showInNavigation": {
            "type": "boolean",
            "description": "Whether the page appears in the navigation menu.",
            "nullable": true
          },
          "parentSlug": {
            "maxLength": 100,
            "type": "string",
            "description": "Slug of the parent page. Pass `null` to move it to the top level.",
            "nullable": true
          },
          "pageType": {
            "$ref": "#/components/schemas/PublicContentPageType"
          },
          "excerpt": {
            "maxLength": 1000,
            "type": "string",
            "description": "Short summary for list cards and RSS. Pass `null` to clear.",
            "nullable": true
          },
          "featuredImageUrl": {
            "maxLength": 1000,
            "type": "string",
            "description": "Cover image. Pass `null` to clear.",
            "nullable": true
          },
          "authorName": {
            "maxLength": 200,
            "type": "string",
            "description": "Displayed author. Pass `null` to clear.",
            "nullable": true
          },
          "publishDate": {
            "type": "string",
            "description": "Editorial publication date. Pass `null` to clear.",
            "format": "date-time",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replaces the whole tag list. Pass `null` to clear.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchCustomerRequest": {
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "type": "string",
            "description": "Full company or person name.",
            "nullable": true
          },
          "organizationNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Company registration number / org.nr. Pass `null` to clear.",
            "nullable": true
          },
          "vatNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "VAT registration number. Pass `null` to clear.",
            "nullable": true
          },
          "invoiceEmail": {
            "maxLength": 200,
            "type": "string",
            "description": "Email address for invoices and order confirmations. Pass `null` to clear.",
            "format": "email",
            "nullable": true
          },
          "phone": {
            "maxLength": 50,
            "type": "string",
            "description": "Primary phone number. Pass `null` to clear.",
            "nullable": true
          },
          "street1": {
            "maxLength": 200,
            "type": "string",
            "description": "Street address line 1. Pass `null` to clear.",
            "nullable": true
          },
          "street2": {
            "maxLength": 200,
            "type": "string",
            "description": "Street address line 2 — suite, c/o, etc. Pass `null` to clear.",
            "nullable": true
          },
          "postalCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Postal / ZIP code. Pass `null` to clear.",
            "nullable": true
          },
          "city": {
            "maxLength": 100,
            "type": "string",
            "description": "City name. Pass `null` to clear.",
            "nullable": true
          },
          "countryCode": {
            "maxLength": 2,
            "pattern": "^[A-Z]{2}$",
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`, `DE`. Pass `null` to clear.",
            "nullable": true
          },
          "defaultCurrencyCode": {
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency code, e.g. `SEK`, `EUR`. Pass `null` to clear.",
            "nullable": true
          },
          "notes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text internal notes. Pass `null` to clear.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the customer is active. Inactive customers cannot be placed on new orders.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchItemAssetRequest": {
        "type": "object",
        "properties": {
          "category": {
            "maxLength": 100,
            "type": "string",
            "description": "For an image, its role: `MainImage`, `GalleryImage`, `LifestyleImage`,\n`TechnicalImage` or `VariantImage`. For a document, the code of one of the tenant's\nactive document categories, such as `Datasheet`, `Manual` or `CadDrawing`.\nCannot be null.",
            "nullable": true
          },
          "displayName": {
            "maxLength": 255,
            "type": "string",
            "description": "Display name in listings. Pass `null` to fall back to the file name.",
            "nullable": true
          },
          "altText": {
            "maxLength": 255,
            "type": "string",
            "description": "Alt text for accessibility and SEO. Pass `null` to clear.",
            "nullable": true
          },
          "description": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text description. Pass `null` to clear.",
            "nullable": true
          },
          "languageCode": {
            "maxLength": 5,
            "type": "string",
            "description": "ISO 639-1 code when the file is language-specific, e.g. `sv`. Pass `null` to make it\nlanguage-neutral.",
            "nullable": true
          },
          "sortOrder": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Position among the item's files; lower comes first. The item's primary image is always listed\nfirst regardless.",
            "format": "int32",
            "nullable": true
          },
          "isPrimary": {
            "type": "boolean",
            "description": "`true` makes this image the item's primary image; the previous one loses the flag. Only\n            `true` is accepted — an item keeps a primary image until another one takes over.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchItemChannelRequest": {
        "type": "object",
        "properties": {
          "isActive": {
            "type": "boolean",
            "description": "Whether the publication is live.",
            "nullable": true
          },
          "name": {
            "maxLength": 200,
            "type": "string",
            "description": "Channel-specific name. Pass `null` to fall back to the item's own.",
            "nullable": true
          },
          "description": {
            "maxLength": 4000,
            "type": "string",
            "description": "Channel-specific long description. Pass `null` to fall back.",
            "nullable": true
          },
          "shortDescription": {
            "maxLength": 500,
            "type": "string",
            "description": "Channel-specific short description. Pass `null` to fall back.",
            "nullable": true
          },
          "metaTitle": {
            "maxLength": 100,
            "type": "string",
            "description": "SEO meta title. Pass `null` to clear.",
            "nullable": true
          },
          "metaDescription": {
            "maxLength": 300,
            "type": "string",
            "description": "SEO meta description. Pass `null` to clear.",
            "nullable": true
          },
          "slug": {
            "maxLength": 200,
            "pattern": "^[a-z0-9-]+$",
            "type": "string",
            "description": "URL slug in this channel. Changing it creates a 301 redirect from the old one.",
            "nullable": true
          },
          "displayCategoryCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Category the item is displayed under here. Pass `null` to use its primary category.",
            "nullable": true
          },
          "showStock": {
            "type": "boolean",
            "description": "Whether stock is shown for this item here.",
            "nullable": true
          },
          "stockDisplayMode": {
            "$ref": "#/components/schemas/PublicStockDisplayMode"
          },
          "allowBackorder": {
            "type": "boolean",
            "description": "Backorder override. Pass `null` to inherit from the item, then the channel.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order within the channel.",
            "format": "int32",
            "nullable": true
          },
          "isFeatured": {
            "type": "boolean",
            "description": "Whether the item is featured here.",
            "nullable": true
          },
          "publishDate": {
            "type": "string",
            "description": "When the item becomes visible. Pass `null` for immediately.",
            "format": "date-time",
            "nullable": true
          },
          "unpublishDate": {
            "type": "string",
            "description": "When the item stops being visible. Pass `null` for never.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchItemRequest": {
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "type": "string",
            "description": "Display name / product name.",
            "nullable": true
          },
          "description": {
            "maxLength": 2000,
            "type": "string",
            "description": "Long-form description, e.g. for a webshop product page. Pass `null` to clear.",
            "nullable": true
          },
          "barcode": {
            "maxLength": 50,
            "type": "string",
            "description": "EAN / GTIN barcode or other scanning code. Pass `null` to clear.",
            "nullable": true
          },
          "costPrice": {
            "type": "number",
            "description": "Purchase / cost price in the tenant default currency. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "salesPrice": {
            "type": "number",
            "description": "Default sales price in the tenant default currency. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "netWeight": {
            "type": "number",
            "description": "Net weight in kilograms. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "width": {
            "type": "number",
            "description": "Width in centimetres. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "height": {
            "type": "number",
            "description": "Height in centimetres. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "depth": {
            "type": "number",
            "description": "Depth in centimetres. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "hsCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Harmonized System (HS / KN) customs tariff code. Pass `null` to clear.",
            "nullable": true
          },
          "countryOfOrigin": {
            "pattern": "^[A-Z]{2}$",
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country of manufacture, e.g. `SE`, `CN`. Pass `null` to clear.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicItemStatus"
          },
          "itemType": {
            "$ref": "#/components/schemas/PublicItemType"
          },
          "salesStartDate": {
            "type": "string",
            "description": "Date from which the item can be sold. Pass `null` to clear.",
            "format": "date",
            "nullable": true
          },
          "salesEndDate": {
            "type": "string",
            "description": "Date until which the item can be sold. Pass `null` to clear.",
            "format": "date",
            "nullable": true
          },
          "allowPreOrder": {
            "type": "boolean",
            "description": "Whether customers can pre-order the item before it is in stock.",
            "nullable": true
          },
          "allowBackorder": {
            "type": "boolean",
            "description": "Whether customers can back-order the item when it is out of stock.",
            "nullable": true
          },
          "categoryCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the item's main category — the one listed with `isPrimary: true` under the\nitem's categories. A category counts as main when its category type is the primary one, or\nwhen it has no category type at all. Pass `null` to remove the main category. Only the\nmain category changes: categories with `isPrimary: false` are left untouched and are\nmanaged with POST and DELETE /preview/items/{itemNumber}/categories. The category must\nalready exist — create it with POST /preview/categories.",
            "nullable": true
          },
          "brandCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the brand. Pass `null` to clear it. The brand must already exist — create it\nwith POST /preview/brands.",
            "nullable": true
          },
          "unitCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Code of the base unit of measure, for example `ST`.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchItemWarehouseRequest": {
        "type": "object",
        "properties": {
          "isActive": {
            "type": "boolean",
            "description": "Whether the item is active in this warehouse. Cannot be null.",
            "nullable": true
          },
          "minQuantity": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Reorder point. Must not exceed maxQuantity. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "maxQuantity": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Maximum stock level. Required by `FillToMax`. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "reorderQuantity": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Quantity ordered by `FixedReorderQuantity`. Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "safetyStock": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Safety stock. Pass `null` to let MRP use the calculated safety stock.",
            "format": "double",
            "nullable": true
          },
          "leadTimeDays": {
            "maximum": 365,
            "minimum": 0,
            "type": "integer",
            "description": "Lead time in calendar days in this warehouse. Pass `null` to clear.",
            "format": "int32",
            "nullable": true
          },
          "lotSizing": {
            "$ref": "#/components/schemas/PublicLotSizingPolicy"
          },
          "supplyPolicy": {
            "$ref": "#/components/schemas/PublicSupplyPolicy"
          },
          "replenishmentType": {
            "$ref": "#/components/schemas/PublicReplenishmentType"
          },
          "importance": {
            "$ref": "#/components/schemas/PublicItemImportance"
          },
          "serviceLevelOverride": {
            "type": "number",
            "description": "Service level between 0 and 1, e.g. `\"0.95\"`. Pass `null` to use the one implied by importance.",
            "format": "double",
            "nullable": true
          },
          "transferFromWarehouseCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Source warehouse for `Transfer`. Pass `null` to use the warehouse's own source.",
            "nullable": true
          },
          "transferLeadTimeDays": {
            "maximum": 365,
            "minimum": 0,
            "type": "integer",
            "description": "Transport time in days from the source warehouse. Pass `null` to use the warehouse's own.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchMediaAssetRequest": {
        "type": "object",
        "properties": {
          "folder": {
            "$ref": "#/components/schemas/PublicChannelMediaFolder"
          },
          "folderId": {
            "type": "string",
            "description": "Move the asset into this folder. Like `folder`, the stored file and its url stay where\nthey are. Cannot be combined with `folder`.",
            "format": "uuid",
            "nullable": true
          },
          "title": {
            "maxLength": 200,
            "type": "string",
            "description": "Display name in the library. Pass `null` to fall back to the file name.",
            "nullable": true
          },
          "altText": {
            "maxLength": 255,
            "type": "string",
            "description": "Alt text for accessibility. Pass `null` to clear.",
            "nullable": true
          },
          "caption": {
            "maxLength": 500,
            "type": "string",
            "description": "Caption. Pass `null` to clear.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchOrderLineRequest": {
        "type": "object",
        "properties": {
          "quantity": {
            "type": "number",
            "description": "Ordered quantity. Must be greater than zero. Cannot be null.",
            "format": "double",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Net unit price in the order currency. Cannot be null.",
            "format": "double",
            "nullable": true
          },
          "discountPercent": {
            "type": "number",
            "description": "Line discount in percent (0–100). Pass `null` to clear.",
            "format": "double",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure code, e.g. `st`, `kg`.",
            "nullable": true
          },
          "requestedDeliveryDate": {
            "type": "string",
            "description": "Requested delivery date for this line. Pass `null` to clear.",
            "format": "date",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text line notes. Pass `null` to clear.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Customer-facing line text. Defaults to the item name when the line was created. Pass `null` to fall back to the item name again.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchPurchaseOrderLineRequest": {
        "type": "object",
        "properties": {
          "quantity": {
            "type": "number",
            "description": "Ordered quantity. Must be greater than zero. Cannot be null.",
            "format": "double",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Purchase price per unit in the order currency. Cannot be null.",
            "format": "double",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure code, e.g. `st`, `kg`. Cannot be null.",
            "nullable": true
          },
          "expectedDate": {
            "type": "string",
            "description": "Expected delivery date for this line. Pass `null` to clear.",
            "format": "date",
            "nullable": true
          },
          "promisedDeliveryDate": {
            "type": "string",
            "description": "Delivery date promised by the supplier. Pass `null` to clear.",
            "format": "date",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text line notes. Pass `null` to clear.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchPurchaseOrderRequest": {
        "type": "object",
        "properties": {
          "orderDate": {
            "type": "string",
            "description": "Order date. Cannot be null.",
            "format": "date",
            "nullable": true
          },
          "expectedDeliveryDate": {
            "type": "string",
            "description": "Date the goods are expected to arrive. Pass `null` to clear.",
            "format": "date",
            "nullable": true
          },
          "promisedDeliveryDate": {
            "type": "string",
            "description": "Delivery date promised by the supplier. Pass `null` to clear.",
            "format": "date",
            "nullable": true
          },
          "warehouseCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the warehouse to receive into. Cannot be null.",
            "nullable": true
          },
          "currencyCode": {
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency code, e.g. `SEK`, `EUR`. Cannot be null.",
            "nullable": true
          },
          "paymentTermCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Payment term code. Pass `null` to clear.",
            "nullable": true
          },
          "deliveryTermCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Delivery term / Incoterm code. Pass `null` to clear.",
            "nullable": true
          },
          "shippingMethodCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Shipping method / carrier code. Pass `null` to clear.",
            "nullable": true
          },
          "supplierReference": {
            "maxLength": 100,
            "type": "string",
            "description": "Our reference at the supplier, or the supplier's order number. Pass `null` to clear.",
            "nullable": true
          },
          "externalNotes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text notes printed on the purchase order document. Pass `null` to clear.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchRedirectRequest": {
        "type": "object",
        "properties": {
          "toPath": {
            "maxLength": 2000,
            "type": "string",
            "description": "Where to send the visitor: a path starting with `/` or an absolute http(s) URL.",
            "nullable": true
          },
          "statusCode": {
            "type": "integer",
            "description": "301 (permanent) or 302 (temporary).",
            "format": "int32",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the web shop applies the redirect.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchShipmentRequest": {
        "type": "object",
        "properties": {
          "trackingNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Carrier tracking number, for shipments booked outside Fluit. Pass `null` to clear.",
            "nullable": true
          },
          "shippingMethodCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the shipping method the goods actually went with, e.g. the carrier's service once the\nforwarder has chosen it. Its tracking-link template turns the tracking number into a link for\nthe customer. Cannot be null.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchSupplierItemRequest": {
        "type": "object",
        "properties": {
          "leadTimeDays": {
            "maximum": 365,
            "minimum": 0,
            "type": "integer",
            "description": "Lead time in calendar days for this item from this supplier. Pass `null` to clear.",
            "format": "int32",
            "nullable": true
          },
          "minOrderQuantity": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Minimum order quantity, greater than 0. Pass `null` for no minimum.",
            "format": "double",
            "nullable": true
          },
          "orderMultiple": {
            "maximum": 99999999999999.9999,
            "minimum": 0,
            "type": "number",
            "description": "Order quantities are rounded up to a multiple of this, greater than 0. Pass `null` for no restriction.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchSupplierRequest": {
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "type": "string",
            "description": "Full company name.",
            "nullable": true
          },
          "organizationNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Company registration number / org.nr. Pass `null` to clear.",
            "nullable": true
          },
          "vatNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "EU VAT registration number, e.g. `SE556012345601`. Changing it re-runs the background VIES validation. Pass `null` to clear.",
            "nullable": true
          },
          "contactPerson": {
            "maxLength": 200,
            "type": "string",
            "description": "Primary contact person at the supplier. Pass `null` to clear.",
            "nullable": true
          },
          "purchaseOrderEmail": {
            "maxLength": 200,
            "type": "string",
            "description": "Email address purchase orders are sent to. Pass `null` to clear.",
            "format": "email",
            "nullable": true
          },
          "phone": {
            "maxLength": 50,
            "type": "string",
            "description": "Primary phone number. Pass `null` to clear.",
            "nullable": true
          },
          "street1": {
            "maxLength": 200,
            "type": "string",
            "description": "Street address line 1. Pass `null` to clear.",
            "nullable": true
          },
          "street2": {
            "maxLength": 200,
            "type": "string",
            "description": "Street address line 2 — c/o, suite, etc. Pass `null` to clear.",
            "nullable": true
          },
          "postalCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Postal / ZIP code. Pass `null` to clear.",
            "nullable": true
          },
          "city": {
            "maxLength": 100,
            "type": "string",
            "description": "City name. Pass `null` to clear.",
            "nullable": true
          },
          "countryCode": {
            "maxLength": 2,
            "pattern": "^[A-Z]{2}$",
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`, `DE`. Pass `null` to clear.",
            "nullable": true
          },
          "currencyCode": {
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency code, e.g. `SEK`, `EUR`. Cannot be null.",
            "nullable": true
          },
          "leadTimeDays": {
            "maximum": 3650,
            "minimum": 0,
            "type": "integer",
            "description": "Default lead time in calendar days. Pass `null` to clear.",
            "format": "int32",
            "nullable": true
          },
          "ourCustomerNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Our customer number at the supplier. Pass `null` to clear.",
            "nullable": true
          },
          "website": {
            "maxLength": 500,
            "type": "string",
            "description": "Supplier website URL. Pass `null` to clear.",
            "nullable": true
          },
          "languageCode": {
            "maxLength": 10,
            "type": "string",
            "description": "ISO 639-1 language code for purchase order documents. Pass `null` to clear.",
            "nullable": true
          },
          "notes": {
            "maxLength": 2000,
            "type": "string",
            "description": "Free-text internal notes. Pass `null` to clear.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the supplier is active. Inactive suppliers cannot be used on new purchase orders.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PatchTicketRequest": {
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 256,
            "type": "string",
            "description": "Short summary of the issue. Cannot be null.",
            "nullable": true
          },
          "description": {
            "maxLength": 4000,
            "type": "string",
            "description": "Full description of the issue. Pass `null` to clear.",
            "nullable": true
          },
          "priority": {
            "$ref": "#/components/schemas/TicketPriority"
          },
          "customerNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Customer the ticket belongs to. Pass `null` to unlink the customer.",
            "nullable": true
          },
          "contactName": {
            "maxLength": 200,
            "type": "string",
            "description": "Name of the person who reported the issue. Pass `null` to clear.",
            "nullable": true
          },
          "contactEmail": {
            "maxLength": 254,
            "type": "string",
            "description": "Email address replies are sent to. Pass `null` to clear.",
            "format": "email",
            "nullable": true
          },
          "contactPhone": {
            "maxLength": 50,
            "type": "string",
            "description": "Phone number of the reporter. Pass `null` to clear.",
            "nullable": true
          },
          "queueCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Ticket queue (team) the ticket is addressed to. Pass `null` to take it out of its queue.",
            "nullable": true
          },
          "itemNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Product the ticket concerns. Pass `null` to unlink the product.",
            "nullable": true
          },
          "serialNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Serial number as the reporter gave it. Pass `null` to clear.",
            "nullable": true
          },
          "firmwareVersion": {
            "maxLength": 50,
            "type": "string",
            "description": "Firmware version in the unit when the fault occurred. Pass `null` to clear.",
            "nullable": true
          },
          "hardwareRevision": {
            "maxLength": 50,
            "type": "string",
            "description": "Hardware revision or batch of the unit. Pass `null` to clear.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PickShipmentRequest": {
        "type": "object",
        "properties": {
          "completeWhenFullyPicked": {
            "type": "boolean",
            "description": "Advance the shipment to Picked when every line came out picked. Default true.\nSet false to keep picking open across several calls."
          }
        },
        "additionalProperties": false
      },
      "PickShipmentResponse": {
        "type": "object",
        "properties": {
          "pickedCount": {
            "type": "integer",
            "description": "Number of lines that were picked by this call.",
            "format": "int32"
          },
          "skipped": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PickShipmentSkippedLineResponse"
            },
            "description": "Lines that could not be picked automatically, with the reason.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicShipmentStatus"
          }
        },
        "additionalProperties": false
      },
      "PickShipmentSkippedLineResponse": {
        "type": "object",
        "properties": {
          "orderLineNumber": {
            "type": "integer",
            "description": "Order line number of the line that was skipped.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number on the skipped line.",
            "nullable": true
          },
          "reason": {
            "type": "string",
            "description": "Why the line could not be picked automatically.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PickTransferOrderLineRequest": {
        "required": [
          "fromLocationCode"
        ],
        "type": "object",
        "properties": {
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Quantity picked. Must be greater than zero and at most what is left to pick on the line.",
            "format": "double"
          },
          "fromLocationCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Location in the source warehouse the goods are taken from."
          },
          "batchNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Batch / lot number. Required when the location holds the item in more than one batch.",
            "nullable": true
          },
          "serialNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Serial number, for serial-tracked items. Picks exactly that unit.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": { }
      },
      "PublicArticleSourceType": {
        "enum": [
          "All",
          "BlogPosts",
          "News"
        ],
        "type": "string",
        "description": "Which content pages a PublicApi.Preview.ContentPages.Queries.PublicPageSectionType.LatestArticles section lists.\nMirrors `Domain.Ecom.ArticleSourceType`."
      },
      "PublicAssetType": {
        "enum": [
          "Image",
          "Document"
        ],
        "type": "string",
        "description": "Type of an item asset. Mirrors `Domain.Items.AssetType`."
      },
      "PublicAttributeDataType": {
        "enum": [
          "Text",
          "WholeNumber",
          "DecimalNumber",
          "Boolean",
          "Date",
          "Url",
          "Html",
          "Color"
        ],
        "type": "string",
        "description": "Data type of a product attribute value. Mirrors `Domain.Items.AttributeDataType`.\nDetermines how `attributes[].value` is formatted in responses and parsed in requests."
      },
      "PublicAttributeResponse": {
        "required": [
          "code",
          "name"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable code, e.g. `material`. This is what you pass when setting a value.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name, e.g. `Material`.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Administrator-facing description of what the attribute means.",
            "nullable": true
          },
          "dataType": {
            "$ref": "#/components/schemas/PublicAttributeDataType"
          },
          "unit": {
            "type": "string",
            "description": "Unit shown after the value, e.g. `kg`. Null when the attribute has no unit.",
            "nullable": true
          },
          "group": {
            "type": "string",
            "description": "Group the attribute is shown under, e.g. `Dimensions`.",
            "nullable": true
          },
          "hasPredefinedValues": {
            "type": "boolean",
            "description": "True when the attribute takes its value from PublicApi.Preview.Items.Queries.PublicAttributeResponse.AllowedValues rather than\nfree input."
          },
          "allowedValues": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The permitted values when PublicApi.Preview.Items.Queries.PublicAttributeResponse.HasPredefinedValues is true.",
            "nullable": true
          },
          "minValue": {
            "type": "number",
            "description": "Lowest accepted value for a numeric attribute. Null means no lower bound.",
            "format": "double",
            "nullable": true
          },
          "maxValue": {
            "type": "number",
            "description": "Highest accepted value for a numeric attribute. Null means no upper bound.",
            "format": "double",
            "nullable": true
          },
          "pattern": {
            "type": "string",
            "description": "Regular expression a text value must match in full. Null means no pattern is enforced.",
            "nullable": true
          },
          "isMultiValue": {
            "type": "boolean",
            "description": "True when an item may hold several values for this attribute."
          },
          "isVisibleOnProductPage": {
            "type": "boolean",
            "description": "True when the attribute is shown on the product page in the web shop."
          }
        },
        "additionalProperties": false,
        "description": "An attribute definition — what an item's specification rows can hold."
      },
      "PublicBrandResponse": {
        "required": [
          "code",
          "name"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Business key. Stable, and what item rows reference.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "logoUrl": {
            "type": "string",
            "nullable": true
          },
          "websiteUrl": {
            "type": "string",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          },
          "createdDate": {
            "type": "string",
            "format": "date-time"
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A brand as the public API exposes it."
      },
      "PublicCardVariant": {
        "enum": [
          "Icon",
          "ImageTop",
          "ImageLeft",
          "Figure"
        ],
        "type": "string",
        "description": "How the cards of a FeatureCards section are drawn. Mirrors `Domain.Ecom.CardVariant`."
      },
      "PublicCategoryImageAspect": {
        "enum": [
          "Portrait",
          "Square",
          "Landscape"
        ],
        "type": "string",
        "description": "Image ratio for categories drawn as tiles or cards. Mirrors `Domain.Ecom.CategoryImageAspect`."
      },
      "PublicCategoryLayout": {
        "enum": [
          "Badge",
          "Tile",
          "Card"
        ],
        "type": "string",
        "description": "How the categories of a Categories section are drawn. Mirrors `Domain.Ecom.CategoryLayout`."
      },
      "PublicCategoryResponse": {
        "required": [
          "code",
          "name"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Business key. Stable, and what item rows reference.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "parentCode": {
            "type": "string",
            "description": "Code of the parent category, or null for a root category.",
            "nullable": true
          },
          "slug": {
            "type": "string",
            "description": "URL segment used by the web shop.",
            "nullable": true
          },
          "metaTitle": {
            "type": "string",
            "description": "Title of the category page in search results. Null = the web shop builds it from the name.",
            "nullable": true
          },
          "metaDescription": {
            "type": "string",
            "description": "Description of the category page in search results. Null = the web shop uses the description.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "isActive": {
            "type": "boolean"
          },
          "createdDate": {
            "type": "string",
            "format": "date-time"
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "An item category as the public API exposes it."
      },
      "PublicChannelHomePageResponse": {
        "required": [
          "channelCode",
          "config"
        ],
        "type": "object",
        "properties": {
          "channelCode": {
            "type": "string",
            "description": "The channel whose home page this is.",
            "nullable": true
          },
          "config": {
            "$ref": "#/components/schemas/PublicPageConfig"
          },
          "modifiedDate": {
            "type": "string",
            "description": "When the storefront configuration was last changed (UTC), or null if never.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A channel's home page: the section list the storefront renders at its root."
      },
      "PublicChannelMediaFolder": {
        "enum": [
          "Hero",
          "Banner",
          "Sections",
          "Content",
          "Documents"
        ],
        "type": "string",
        "description": "Where in the storefront a media file belongs. Filters the library, and decides the folder a\n<em>new</em> upload is stored under."
      },
      "PublicChannelResponse": {
        "required": [
          "allowGuestPrices",
          "channelCode",
          "createdDate",
          "defaultLanguage",
          "isActive",
          "name",
          "type"
        ],
        "type": "object",
        "properties": {
          "channelCode": {
            "type": "string",
            "description": "Stable channel code, e.g. `webshop-se`. The business key used in URLs.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name, e.g. \"Webshop Sverige\".",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/PublicSalesChannelType"
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the channel is active and may be sold through."
          },
          "defaultLanguage": {
            "type": "string",
            "description": "Default language as ISO 639-1, e.g. `sv`. Drives order confirmations and documents.",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "Default currency as ISO 4217, e.g. `SEK`.",
            "nullable": true
          },
          "defaultWarehouseCode": {
            "type": "string",
            "description": "Code of the warehouse orders in this channel are fulfilled from by default.",
            "nullable": true
          },
          "defaultPriceListCode": {
            "type": "string",
            "description": "Code of the price list applied in this channel, when one is configured.",
            "nullable": true
          },
          "orderTypeCode": {
            "type": "string",
            "description": "Code of the order type orders in this channel are created with.",
            "nullable": true
          },
          "allowGuestPrices": {
            "type": "boolean",
            "description": "Whether prices are shown to visitors who are not logged in."
          },
          "createdDate": {
            "type": "string",
            "description": "When the channel was created (UTC).",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "When the channel was last changed (UTC), or null if never changed since creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A sales channel — the commercial terms a storefront, portal or marketplace sells on."
      },
      "PublicConfigurationCalculationResponse": {
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "description": "Item number of the configured product.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the configured product.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "The quantity the price was calculated for.",
            "format": "double"
          },
          "isValid": {
            "type": "boolean",
            "description": "Whether the configuration is complete and within bounds. When false, the price fields are null."
          },
          "validationErrors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationValidationError"
            },
            "description": "Every problem found, one entry per offending feature. Empty when `isValid` is true.",
            "nullable": true
          },
          "resolvedValues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationResolvedValue"
            },
            "description": "The resolved numeric values, including those derived by formula (area, fabric consumption, …). Show these back to the customer. Empty when the configuration is invalid.",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 code the amounts below are expressed in. Null when the configuration is invalid.",
            "nullable": true
          },
          "basePricePerUnit": {
            "type": "number",
            "description": "The item's own price per unit from the price engine — the same number GET /preview/items/{itemNumber}/price returns. Null when the configuration is invalid.",
            "format": "double",
            "nullable": true
          },
          "configurationSurchargePerUnit": {
            "type": "number",
            "description": "What the chosen options add per unit. Null when the configuration is invalid.",
            "format": "double",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Base price plus surcharge — the unit price the order line will get. Null when the configuration is invalid.",
            "format": "double",
            "nullable": true
          },
          "totalPrice": {
            "type": "number",
            "description": "Unit price × quantity, excluding VAT, shipping and order-level discounts. Null when the configuration is invalid.",
            "format": "double",
            "nullable": true
          },
          "priceSource": {
            "type": "string",
            "description": "Where the base price came from in the price hierarchy, e.g. `CustomerPriceList`, `ItemSalesPrice`, `NotFound`. Null when the configuration is invalid.",
            "nullable": true
          },
          "priceListName": {
            "type": "string",
            "description": "Name of the price list that produced the base price. Null when no price list matched.",
            "nullable": true
          },
          "components": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationComponent"
            },
            "description": "The exploded bill of materials. Only present when `?includeBreakdown=true`.",
            "nullable": true
          },
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationOperation"
            },
            "description": "The exploded production steps. Only present when `?includeBreakdown=true`.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The result of pricing and validating a configuration, returned by\nPOST /preview/configurations/calculate. Nothing is saved.\n\nAn incomplete or out-of-range configuration is a normal state while the customer is still\nchoosing, so it comes back as `200` with `isValid: false` and every problem listed in\n`validationErrors` — not as an error response. The price fields are then null."
      },
      "PublicConfigurationComponent": {
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "description": "Item number of the component.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the component.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "Quantity needed for the whole configured quantity.",
            "format": "double"
          },
          "unitCode": {
            "type": "string",
            "description": "Code of the component's base unit, e.g. `m`. Null if not set.",
            "nullable": true
          },
          "sourceFeatureCode": {
            "type": "string",
            "description": "Code of the feature that added this component, when it came from a choice rather than the static bill of materials. Null otherwise.",
            "nullable": true
          },
          "isQuantityFromFormula": {
            "type": "boolean",
            "description": "Whether the quantity was computed from a formula (e.g. fabric from width × height) rather than being fixed."
          }
        },
        "additionalProperties": false,
        "description": "A material line the configuration explodes into."
      },
      "PublicConfigurationFeature": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable code — the business key used in `values[].featureCode`, e.g. `WIDTH`. Unique per item.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name / field label, e.g. `Width (cm)`.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Help text for the field. Null if not set.",
            "nullable": true
          },
          "featureType": {
            "$ref": "#/components/schemas/PublicItemFeatureType"
          },
          "isRequired": {
            "type": "boolean",
            "description": "Whether a value is required. A configuration missing a required value is reported as invalid, not rejected."
          },
          "requiresMeasurement": {
            "type": "boolean",
            "description": "Whether the value is expected to come from an on-site measurement rather than being picked by the customer."
          },
          "sortOrder": {
            "type": "integer",
            "description": "Presentation order, ascending.",
            "format": "int32"
          },
          "defaultValue": {
            "type": "string",
            "description": "Default value as a string, to prefill the field. Interpret according to `featureType`. Null if not set.",
            "nullable": true
          },
          "minValue": {
            "type": "number",
            "description": "Lowest accepted value for `Number` features. Null for other types.",
            "format": "double",
            "nullable": true
          },
          "maxValue": {
            "type": "number",
            "description": "Highest accepted value for `Number` features. Null for other types.",
            "format": "double",
            "nullable": true
          },
          "affectsPrice": {
            "type": "boolean",
            "description": "Whether the field's value changes the price."
          },
          "priceImpactPerUnit": {
            "type": "number",
            "description": "Price change per unit of the value, in the tenant base currency. For `Number` it is multiplied\nby the value, for `Boolean` it applies once when true. Null when the field does not affect the\nprice <b>or</b> when its impact is formula-driven — a field can have `affectsPrice` true with a\nnull `priceImpactPerUnit` when the surcharge follows the measurements or the selected article.\nPOST /preview/configurations/calculate is the only place that returns the resulting price.",
            "format": "double",
            "nullable": true
          },
          "condition": {
            "type": "string",
            "description": "Condition for when the field applies, e.g. `MODELL=SWING` or `BREDD>1000`. Null means the\nfield always applies. A configurator should hide the field while the condition is false; a value sent\nfor a hidden field is ignored, and a required hidden field is not reported as missing.\n\nSyntax is `<featureCode><operator><value>`. Number, Boolean and Calculated fields\ncompare with `=`, `<>`, `<`, `>`, `<=` and `>=`;\nSelection and Text compare their option code / text with `=` and `<>` only.",
            "nullable": true
          },
          "selectableItemCategoryCode": {
            "type": "string",
            "description": "For `ItemSelection`: the category the selectable items are restricted to. Pass it as `?categoryCode=` to GET /preview/items to build the picker. Items outside the category are rejected. Null when unrestricted.",
            "nullable": true
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationOption"
            },
            "description": "For `Selection`: the allowed choices, in presentation order. Empty for other types.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One configurable field on an item."
      },
      "PublicConfigurationOperation": {
        "type": "object",
        "properties": {
          "sequence": {
            "type": "integer",
            "description": "Position in the routing, ascending.",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "Name of the step, e.g. `Cut`, `Sew`.",
            "nullable": true
          },
          "plannedDurationMinutes": {
            "type": "integer",
            "description": "Planned duration in minutes, including setup.",
            "format": "int32"
          },
          "setupTimeMinutes": {
            "type": "integer",
            "description": "Setup time in minutes, included in `plannedDurationMinutes`.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A production step the configuration explodes into."
      },
      "PublicConfigurationOption": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable code — the business key used in `values[].optionCode`. Unique per feature.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the choice, e.g. `Natural linen`.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Presentation order, ascending.",
            "format": "int32"
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the preselected choice."
          },
          "priceImpact": {
            "type": "number",
            "description": "Price change when this choice is picked, in the tenant base currency. Null when the choice is free.\n\n<b>Ignored when `linkedItemNumber` is set.</b> A linked item is added to the bill of materials\nas a cost line, not as a sales line, so such a choice does not change the customer's\n`unitPrice` at all. Price a choice by giving it a `priceImpact`<i>without</i> a linked\nitem, or by driving the price from a `Calculated` feature.",
            "format": "double",
            "nullable": true
          },
          "linkedItemNumber": {
            "type": "string",
            "description": "The item this choice adds to the bill of materials, e.g. the actual fabric article. Affects what gets built and its cost, not the sales price — see PublicApi.Preview.Configurations.Queries.PublicConfigurationOption.PriceImpact. Null when the choice has no material of its own.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One allowed choice on a `Selection` feature."
      },
      "PublicConfigurationResolvedValue": {
        "type": "object",
        "properties": {
          "featureCode": {
            "type": "string",
            "description": "Code of the feature.",
            "nullable": true
          },
          "featureName": {
            "type": "string",
            "description": "Display name of the feature.",
            "nullable": true
          },
          "value": {
            "type": "number",
            "description": "The resolved value. Booleans resolve to 1 or 0.",
            "format": "double"
          },
          "isCalculated": {
            "type": "boolean",
            "description": "Whether the value was derived by formula rather than entered by the customer."
          }
        },
        "additionalProperties": false,
        "description": "A resolved numeric value — entered, or derived from other values by a formula."
      },
      "PublicConfigurationResponse": {
        "type": "object",
        "properties": {
          "configurationNumber": {
            "type": "string",
            "description": "Unique configuration number — business key, e.g. `WO-1042`. Use it in every follow-up call.",
            "nullable": true
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number of the configured product.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the configured product.",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Free-text title. Defaults to the item name when not supplied.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Free-text description, e.g. which window the curtain is for. Null if not set.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "How many units of the configured product. Expressed in the item's base unit.",
            "format": "double"
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number the configuration belongs to. Required before it can become an order. Null when the configuration is anonymous.",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "description": "Customer name. Null when the configuration is anonymous.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Warehouse code the configuration is planned against. Null when not set.",
            "nullable": true
          },
          "values": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationValue"
            },
            "description": "The chosen values, one per feature that has a value.",
            "nullable": true
          },
          "configurationPriceImpact": {
            "type": "number",
            "description": "Total configuration surcharge for the whole quantity, in the tenant base currency, before the price engine runs. The priced fields below express the same thing in the customer's currency.",
            "format": "double"
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 code the priced fields below are expressed in. Null on the list endpoint — see the note on PublicApi.Preview.Configurations.Queries.PublicConfigurationResponse.UnitPrice.",
            "nullable": true
          },
          "basePricePerUnit": {
            "type": "number",
            "description": "The item's own price per unit from the price engine. Null on the list endpoint.",
            "format": "double",
            "nullable": true
          },
          "configurationSurchargePerUnit": {
            "type": "number",
            "description": "What the chosen options add per unit. Null on the list endpoint.",
            "format": "double",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Base price plus surcharge — the unit price the order line will get, priced as of now.\n\nOnly populated when a single configuration is returned (create, get by number, reconfigure).\nOn GET /preview/configurations it is `null`: pricing a whole page would mean one price\nengine run per row. Read one configuration, or use POST /preview/configurations/calculate,\nwhen you need the price for a list.",
            "format": "double",
            "nullable": true
          },
          "totalPrice": {
            "type": "number",
            "description": "Unit price × quantity, excluding VAT, freight and order-level discounts. Null on the list endpoint.",
            "format": "double",
            "nullable": true
          },
          "priceSource": {
            "type": "string",
            "description": "Where the base price came from in the price hierarchy, e.g. `CustomerPriceList`. Null on the list endpoint.",
            "nullable": true
          },
          "priceListName": {
            "type": "string",
            "description": "Name of the price list that produced the base price. Null when no price list matched or on the list endpoint.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the configuration was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A saved configuration — a specific set of choices for a configurable item, priced and ready to be\nturned into a sales order. Returned by POST /preview/configurations, GET /preview/configurations\nand POST /preview/configurations/{configurationNumber}/reconfigure."
      },
      "PublicConfigurationValidationError": {
        "type": "object",
        "properties": {
          "featureCode": {
            "type": "string",
            "description": "Code of the feature the problem belongs to.",
            "nullable": true
          },
          "code": {
            "type": "string",
            "description": "Stable error code, e.g. `FeatureExplosion.RequiredFeatureMissing`, `FeatureExplosion.ValueOutOfRange`, `FeatureExplosion.InvalidOption`.",
            "nullable": true
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A problem with one chosen value, meant to be shown at the corresponding form field."
      },
      "PublicConfigurationValue": {
        "type": "object",
        "properties": {
          "featureCode": {
            "type": "string",
            "description": "Code of the feature this value belongs to.",
            "nullable": true
          },
          "featureName": {
            "type": "string",
            "description": "Display name of the feature.",
            "nullable": true
          },
          "featureType": {
            "$ref": "#/components/schemas/PublicItemFeatureType"
          },
          "number": {
            "type": "number",
            "description": "Numeric value, for `Number` and `Calculated` features. Null otherwise.",
            "format": "double",
            "nullable": true
          },
          "text": {
            "type": "string",
            "description": "Text value, for `Text` features. Null otherwise.",
            "nullable": true
          },
          "boolean": {
            "type": "boolean",
            "description": "Boolean value, for `Boolean` features. Null otherwise.",
            "nullable": true
          },
          "optionCode": {
            "type": "string",
            "description": "Code of the chosen option, for `Selection` features. Null otherwise.",
            "nullable": true
          },
          "optionName": {
            "type": "string",
            "description": "Display name of the chosen option. Null unless `optionCode` is set.",
            "nullable": true
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number of the chosen item, for `ItemSelection` features. Null otherwise.",
            "nullable": true
          },
          "isMeasured": {
            "type": "boolean",
            "description": "Whether the value came from an on-site measurement."
          }
        },
        "additionalProperties": false,
        "description": "One chosen value on a saved configuration. Exactly one value field is set, matching `featureType`."
      },
      "PublicConfigurationValueInput": {
        "required": [
          "featureCode"
        ],
        "type": "object",
        "properties": {
          "featureCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Code of the feature being set, e.g. `WIDTH`. Must exist on the item."
          },
          "number": {
            "type": "number",
            "description": "Value for a `Number` feature, e.g. `\"240\"`.",
            "format": "double",
            "nullable": true
          },
          "text": {
            "maxLength": 500,
            "type": "string",
            "description": "Value for a `Text` feature.",
            "nullable": true
          },
          "boolean": {
            "type": "boolean",
            "description": "Value for a `Boolean` feature.",
            "nullable": true
          },
          "optionCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the chosen option for a `Selection` feature. Must belong to that feature.",
            "nullable": true
          },
          "itemNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Item number of the chosen item for an `ItemSelection` feature.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One chosen value in a configuration request. Shared by POST /preview/configurations/calculate,\nPOST /preview/configurations and POST /preview/configurations/{configurationNumber}/reconfigure\nso the same payload works throughout the flow.\n\nSend exactly the field that matches the feature's `featureType` from\nGET /preview/items/{itemNumber}/configuration; the others are ignored. `Calculated` features\ntake no input — their result comes back in `resolvedValues`."
      },
      "PublicContentPageResponse": {
        "required": [
          "channelCode",
          "config",
          "createdDate",
          "isPublished",
          "pageType",
          "showInNavigation",
          "slug",
          "sortOrder",
          "title"
        ],
        "type": "object",
        "properties": {
          "channelCode": {
            "type": "string",
            "description": "The channel the page belongs to.",
            "nullable": true
          },
          "slug": {
            "type": "string",
            "description": "URL slug, unique within the channel.",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Page title, used for the heading and as the SEO title.",
            "nullable": true
          },
          "pageType": {
            "$ref": "#/components/schemas/PublicContentPageType"
          },
          "metaDescription": {
            "type": "string",
            "description": "SEO meta description.",
            "nullable": true
          },
          "isPublished": {
            "type": "boolean",
            "description": "Whether the page is published and visible in the storefront."
          },
          "publishedAt": {
            "type": "string",
            "description": "When it was published (UTC), or null if it never has been.",
            "format": "date-time",
            "nullable": true
          },
          "publishDate": {
            "type": "string",
            "description": "Editorial publication date shown and sorted on. May be in the future: public storefront\nqueries hide an article until it passes.",
            "format": "date-time",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order in listings and navigation.",
            "format": "int32"
          },
          "showInNavigation": {
            "type": "boolean",
            "description": "Whether the page appears in the navigation menu."
          },
          "parentSlug": {
            "type": "string",
            "description": "Slug of the parent page, for a hierarchy. Null at the top level.",
            "nullable": true
          },
          "excerpt": {
            "type": "string",
            "description": "Short summary for list cards, RSS and meta. Articles only.",
            "nullable": true
          },
          "featuredImageUrl": {
            "type": "string",
            "description": "Cover image for list cards and Open Graph. Articles only.",
            "nullable": true
          },
          "authorName": {
            "type": "string",
            "description": "Displayed author. Free text, not linked to a user.",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tags used for filtering and related articles.",
            "nullable": true
          },
          "config": {
            "$ref": "#/components/schemas/PublicPageConfig"
          },
          "createdDate": {
            "type": "string",
            "description": "When the page was created (UTC).",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "When the page was last changed (UTC), or null if never changed.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "An editorial page in a channel: a standing page, a blog post or a news item."
      },
      "PublicContentPageType": {
        "enum": [
          "Page",
          "BlogPost",
          "NewsPost",
          "Home"
        ],
        "type": "string",
        "description": "What kind of content page this is. Mirrors `Domain.Ecom.ContentPageType`."
      },
      "PublicCostPriceMethod": {
        "enum": [
          "Manual",
          "WeightedAverage",
          "LastPurchasePrice",
          "PrimarySupplier",
          "BomRollup"
        ],
        "type": "string",
        "description": "How `costPrice` is maintained. Mirrors `Domain.Items.CostPriceMethod`.\n\nAnything other than PublicApi.Preview.Items.Queries.PublicCostPriceMethod.Manual means the ERP recalculates the cost price on stock and\nsupplier price changes — a value written through the API will not necessarily stay put."
      },
      "PublicCrossReferenceType": {
        "enum": [
          "Manufacturer",
          "Oem",
          "IndustryStandard",
          "Superseded",
          "Competitor",
          "Barcode",
          "Custom"
        ],
        "type": "string",
        "description": "Type of an alternative item identifier. Mirrors `Domain.Items.CrossReferenceType`."
      },
      "PublicCurrencyResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "ISO 4217 currency code, e.g. `SEK`, `EUR`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the currency, e.g. `Swedish Krona`.",
            "nullable": true
          },
          "symbol": {
            "type": "string",
            "description": "Currency symbol, e.g. `kr`, `€`. Null if not configured.",
            "nullable": true
          },
          "exchangeRate": {
            "type": "number",
            "description": "Exchange rate relative to the tenant base currency. Serialised as a decimal string.",
            "format": "double"
          },
          "decimalPlaces": {
            "type": "integer",
            "description": "Number of decimal places used when displaying amounts in this currency.",
            "format": "int32"
          },
          "isBase": {
            "type": "boolean",
            "description": "Whether this is the tenant's base / accounting currency."
          }
        },
        "additionalProperties": false,
        "description": "Currency available in the tenant."
      },
      "PublicCustomerAddressResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier of the address.",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Recipient company or person name.",
            "nullable": true
          },
          "street1": {
            "type": "string",
            "description": "Street address line 1.",
            "nullable": true
          },
          "street2": {
            "type": "string",
            "description": "Street address line 2 (c/o, suite, etc.). Null if not set.",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "description": "Postal / ZIP code.",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "City name.",
            "nullable": true
          },
          "countryCode": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`.",
            "nullable": true
          },
          "contactPerson": {
            "type": "string",
            "description": "Contact person at the delivery address. Null if not set.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Phone number at the delivery address. Null if not set.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address at the delivery address. Null if not set.",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the customer's default delivery address."
          }
        },
        "additionalProperties": false,
        "description": "Delivery address registered on a customer."
      },
      "PublicCustomerContactResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier — usable as `customerContactId` in order creation.",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Full name of the contact person.",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Job title, e.g. `Purchasing Manager`. Null if not set.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address. Null if not set.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Phone number. Null if not set.",
            "nullable": true
          },
          "mobile": {
            "type": "string",
            "description": "Mobile phone number. Null if not set.",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the customer's default contact."
          }
        },
        "additionalProperties": false,
        "description": "Contact person registered on a customer."
      },
      "PublicCustomerResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "customerNumber": {
            "type": "string",
            "description": "Unique customer number — business key used in all URL references.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Full company or person name.",
            "nullable": true
          },
          "organizationNumber": {
            "type": "string",
            "description": "Company registration number / org.nr, e.g. `5560001234`. Null if not set.",
            "nullable": true
          },
          "vatNumber": {
            "type": "string",
            "description": "VAT registration number, e.g. `SE556000123401`. Null if not set.",
            "nullable": true
          },
          "invoiceEmail": {
            "type": "string",
            "description": "Primary email address for invoices and order confirmations. Null if not set.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Primary phone number. Null if not set.",
            "nullable": true
          },
          "street1": {
            "type": "string",
            "description": "Street address line 1. Null if not set.",
            "nullable": true
          },
          "street2": {
            "type": "string",
            "description": "Street address line 2 (suite, c/o, etc.). Null if not set.",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "description": "Postal / ZIP code. Null if not set.",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "City name. Null if not set.",
            "nullable": true
          },
          "countryCode": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`, `DE`, `NO`. Null if not set.",
            "nullable": true
          },
          "defaultCurrencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code of the customer's default currency, e.g. `SEK`, `EUR`. Null if not set.",
            "nullable": true
          },
          "paymentTermCode": {
            "type": "string",
            "description": "Code of the customer's default payment term — usable as `paymentTermCode` in order creation. Null if not set.",
            "nullable": true
          },
          "paymentTermName": {
            "type": "string",
            "description": "Name of the customer's default payment term. Null if not set.",
            "nullable": true
          },
          "deliveryTermCode": {
            "type": "string",
            "description": "Code of the customer's default delivery term — usable as `deliveryTermCode` in order creation. Null if not set.",
            "nullable": true
          },
          "deliveryTermName": {
            "type": "string",
            "description": "Name of the customer's default delivery term. Null if not set.",
            "nullable": true
          },
          "customerGroupCode": {
            "type": "string",
            "description": "Code of the customer group this customer belongs to. Null if not set.",
            "nullable": true
          },
          "customerGroupName": {
            "type": "string",
            "description": "Name of the customer group this customer belongs to. Null if not set.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the customer is active. Inactive customers cannot be used on new orders."
          },
          "notes": {
            "type": "string",
            "description": "Free-text internal notes (not visible to the customer). Null if not set.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the customer record was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Customer details returned by GET /preview/customers/{customerNumber} and the list endpoint."
      },
      "PublicDeletionResponse": {
        "type": "object",
        "properties": {
          "resource": {
            "type": "string",
            "description": "Which collection the record belonged to: `customers`, `items`, `suppliers`,\n`orders`, `purchase-orders` or `configurations`. Matches the path segment of\nthe list endpoint the record used to appear in.",
            "nullable": true
          },
          "id": {
            "type": "string",
            "description": "The deleted record's `id`, the same value its list endpoint used to return.",
            "format": "uuid"
          },
          "businessKey": {
            "type": "string",
            "description": "The business key the record had when it was deleted — customer number, item number, order\nnumber. This is normally what you stored on your side, so it is the field to match on.\nNull when the record never had one (an unnumbered draft, for example).",
            "nullable": true
          },
          "deletedDate": {
            "type": "string",
            "description": "UTC timestamp of the deletion. Use the highest value you have seen as the next `?deletedSince=`.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "En borttagen post. Avsiktligt tunn: den svarar på \"vilken post försvann, och när\" — inte på vad\nposten innehöll. Innehållet är borta, och att bevara det i en gravsten vore fel både för lagring\noch för borttagningsförfrågningar."
      },
      "PublicDeliveryAddressResponse": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Recipient company or person name.",
            "nullable": true
          },
          "street1": {
            "type": "string",
            "description": "Street address line 1.",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "description": "Postal / ZIP code.",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "City name.",
            "nullable": true
          },
          "countryCode": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`.",
            "nullable": true
          },
          "street2": {
            "type": "string",
            "description": "Street address line 2 (c/o, suite, etc.). Null if not set.",
            "nullable": true
          },
          "contactPerson": {
            "type": "string",
            "description": "Contact person at the delivery address. Null if not set.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Phone number at the delivery address. Null if not set.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address at the delivery address. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Delivery address attached to a sales order."
      },
      "PublicDeliveryStatus": {
        "enum": [
          "NotDelivered",
          "PartiallyDelivered",
          "FullyDelivered"
        ],
        "type": "string",
        "description": "How much of an order has actually been delivered. Derived from the ordered and\ndelivered quantities on the order lines, so it stays correct for partial deliveries —\nthe common case in B2B, where one line ships today and the rest next week."
      },
      "PublicDeliveryTermResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code used as `deliveryTermCode` in order creation, e.g. `DAP`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the delivery term.",
            "nullable": true
          },
          "isDefaultSales": {
            "type": "boolean",
            "description": "Whether this is the default delivery term for new sales orders."
          }
        },
        "additionalProperties": false,
        "description": "Delivery term / Incoterm available on sales orders and customers."
      },
      "PublicFaqSource": {
        "enum": [
          "Manual",
          "KnowledgeArticles"
        ],
        "type": "string",
        "description": "Where a Faq section's questions come from. Mirrors `Domain.Ecom.FaqSource`."
      },
      "PublicFormAside": {
        "enum": [
          "None",
          "ContactInfo",
          "Text"
        ],
        "type": "string",
        "description": "What stands next to a form. Mirrors `Domain.Ecom.FormAside`."
      },
      "PublicGrade": {
        "enum": [
          "A",
          "B",
          "C",
          "D"
        ],
        "type": "string",
        "description": "Item condition grade (A/B/C-stock) exposed via the Public API. Mirrors `Domain.Items.Grade`."
      },
      "PublicHeroHeight": {
        "enum": [
          "Normal",
          "Compact",
          "Tall",
          "Full"
        ],
        "type": "string",
        "description": "How tall a Background hero is. Mirrors `Domain.Ecom.HeroHeight`."
      },
      "PublicHeroLayout": {
        "enum": [
          "Background",
          "Split"
        ],
        "type": "string",
        "description": "How a Hero section is laid out. Mirrors `Domain.Ecom.HeroLayout`."
      },
      "PublicHeroTextColor": {
        "enum": [
          "Light",
          "Dark"
        ],
        "type": "string",
        "description": "Text colour for a hero section.\nMirrors `Domain.Ecom.HeroTextColor`."
      },
      "PublicInventoryCountResponse": {
        "type": "object",
        "properties": {
          "countNumber": {
            "type": "string",
            "description": "Unique count number.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Warehouse the count covers.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicInventoryCountStatus"
          },
          "type": {
            "type": "string",
            "description": "What determined the scope: Full, Location, Category, ABC, Random or Impulse.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Free-text description. Null if not set.",
            "nullable": true
          },
          "totalLines": {
            "type": "integer",
            "description": "Total number of lines to count.",
            "format": "int32"
          },
          "countedLines": {
            "type": "integer",
            "description": "Number of lines counted so far.",
            "format": "int32"
          },
          "linesWithVariance": {
            "type": "integer",
            "description": "Number of counted lines that differ from the recorded quantity.",
            "format": "int32"
          },
          "totalVarianceValue": {
            "type": "number",
            "description": "Total value of the variances, in the tenant's base currency.",
            "format": "double"
          },
          "startedAt": {
            "type": "string",
            "description": "UTC timestamp when counting started. Null while Draft.",
            "format": "date-time",
            "nullable": true
          },
          "completedAt": {
            "type": "string",
            "description": "UTC timestamp when counting finished. Null until completed.",
            "format": "date-time",
            "nullable": true
          },
          "appliedAt": {
            "type": "string",
            "description": "UTC timestamp when the differences were posted to stock. Null until applied.",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the count was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp when the count was last modified. Null if never modified.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A physical inventory count."
      },
      "PublicInventoryCountStatus": {
        "enum": [
          "Draft",
          "InProgress",
          "Completed",
          "Applied",
          "Cancelled"
        ],
        "type": "string",
        "description": "Status of a physical inventory count."
      },
      "PublicInventoryTransactionResponse": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string",
            "description": "Internal unique identifier of the transaction (UUID v7). Stable, use it to deduplicate.",
            "format": "uuid"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number the movement applies to.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Warehouse code the movement happened in.",
            "nullable": true
          },
          "locationCode": {
            "type": "string",
            "description": "Location code within the warehouse.",
            "nullable": true
          },
          "targetLocationCode": {
            "type": "string",
            "description": "Destination location code. Only set on Transfer movements.",
            "nullable": true
          },
          "transactionType": {
            "$ref": "#/components/schemas/PublicInventoryTransactionType"
          },
          "quantity": {
            "type": "number",
            "description": "Signed quantity: positive increases stock, negative decreases it. Serialised as a decimal string.",
            "format": "double"
          },
          "balanceAfter": {
            "type": "number",
            "description": "On-hand quantity after the movement. Serialised as a decimal string.",
            "format": "double"
          },
          "unitCost": {
            "type": "number",
            "description": "Unit cost booked on the movement, in the tenant's base currency.",
            "format": "double",
            "nullable": true
          },
          "averageCostAfter": {
            "type": "number",
            "description": "Average cost after the movement, in the tenant's base currency.",
            "format": "double"
          },
          "transactionDate": {
            "type": "string",
            "description": "UTC timestamp of the movement.",
            "format": "date-time"
          },
          "referenceType": {
            "type": "string",
            "description": "What the movement originated from, e.g. `SalesOrder`, `PurchaseOrder`. Null if manual.",
            "nullable": true
          },
          "referenceId": {
            "type": "string",
            "description": "Identifier of the originating record, as text. Null if manual.",
            "nullable": true
          },
          "serialNumber": {
            "type": "string",
            "description": "Serial number, for serial-tracked items.",
            "nullable": true
          },
          "batchNumber": {
            "type": "string",
            "description": "Batch / lot number, for batch-tracked items.",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text notes stored on the movement.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single movement in the stock ledger."
      },
      "PublicInventoryTransactionType": {
        "enum": [
          "Receipt",
          "Issue",
          "Adjustment",
          "Transfer",
          "Return",
          "Scrap",
          "ConsignmentConsumption",
          "Revaluation"
        ],
        "type": "string",
        "description": "What caused a stock movement. Mirrors the internal transaction types."
      },
      "PublicInvoiceLineResponse": {
        "type": "object",
        "properties": {
          "lineNumber": {
            "type": "integer",
            "description": "Line number within the invoice, starting at 1.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number of the invoiced item. Null for charge and free-text lines.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Line description as printed on the invoice.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "Invoiced quantity. Serialised as a decimal string.",
            "format": "double"
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure, e.g. `st`.",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Price per unit excluding tax. Serialised as a decimal string.",
            "format": "double"
          },
          "lineTotal": {
            "type": "number",
            "description": "Line total excluding tax. Serialised as a decimal string.",
            "format": "double"
          },
          "taxPercent": {
            "type": "number",
            "description": "Tax rate applied to the line, in percent. Serialised as a decimal string.",
            "format": "double"
          },
          "taxAmount": {
            "type": "number",
            "description": "Tax amount on the line. Serialised as a decimal string.",
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "A single line on an invoice."
      },
      "PublicInvoicePaymentStatus": {
        "enum": [
          "Unpaid",
          "PartiallyPaid",
          "Paid",
          "AwaitingTaxReduction"
        ],
        "type": "string",
        "description": "Payment status exposed via the Public API. Mirrors `Domain.Invoices.InvoicePaymentStatus`."
      },
      "PublicInvoiceResponse": {
        "type": "object",
        "properties": {
          "invoiceNumber": {
            "type": "string",
            "description": "Unique invoice number, e.g. `INV-2026-00042`.",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/PublicInvoiceType"
          },
          "status": {
            "$ref": "#/components/schemas/PublicInvoiceStatus"
          },
          "paymentStatus": {
            "$ref": "#/components/schemas/PublicInvoicePaymentStatus"
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number of the invoice recipient.",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "description": "Display name of the customer.",
            "nullable": true
          },
          "invoiceDate": {
            "type": "string",
            "description": "Invoice date (ISO 8601 date).",
            "format": "date"
          },
          "dueDate": {
            "type": "string",
            "description": "Due date (ISO 8601 date).",
            "format": "date"
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code for all monetary values on this invoice.",
            "nullable": true
          },
          "totalAmount": {
            "type": "number",
            "description": "Total excluding tax. Serialised as a decimal string.",
            "format": "double"
          },
          "totalVat": {
            "type": "number",
            "description": "Total tax. Serialised as a decimal string.",
            "format": "double"
          },
          "paidAmount": {
            "type": "number",
            "description": "Amount received so far. Serialised as a decimal string.",
            "format": "double"
          },
          "balance": {
            "type": "number",
            "description": "Remaining amount to pay, including tax. Serialised as a decimal string.",
            "format": "double"
          },
          "externalDocumentNumber": {
            "type": "string",
            "description": "Document number in the accounting system. Null until the invoice is posted.",
            "nullable": true
          },
          "comments": {
            "type": "string",
            "description": "Free-text comment printed on the invoice. Null if not set.",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicInvoiceLineResponse"
            },
            "description": "Invoice lines. Empty on a list response.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the invoice was created.",
            "format": "date-time"
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "An invoice as exposed by GET /preview/invoices/{invoiceNumber}.\nReference data is addressed by business key, never by internal id."
      },
      "PublicInvoiceStatus": {
        "enum": [
          "Open",
          "Booked",
          "Cancelled"
        ],
        "type": "string",
        "description": "Invoice status values exposed via the Public API.\n\nMirrors `Domain.Invoices.InvoiceStatus` name-for-name and value-for-value so the query\nprojections can cast directly — a cast is translatable to SQL where a switch over a helper\nmethod is not. `PublicInvoiceEnumParityTests` fails the build if the two ever drift apart,\nwhich is what stops a new domain value from silently serialising as a bare number."
      },
      "PublicInvoiceType": {
        "enum": [
          "Invoice",
          "CreditNote",
          "Receipt"
        ],
        "type": "string",
        "description": "Invoice type values exposed via the Public API. Mirrors `Domain.Invoices.InvoiceType`."
      },
      "PublicItemAssetResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier of the asset.",
            "format": "uuid"
          },
          "assetType": {
            "$ref": "#/components/schemas/PublicAssetType"
          },
          "category": {
            "type": "string",
            "description": "Asset category. For an image its role: `MainImage`, `GalleryImage`,\n`LifestyleImage`, `TechnicalImage` or `VariantImage`. For a document the code\nof a document category the tenant defines, e.g. `Datasheet`, `Manual` or a\ntenant's own `Archive`.",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "URL to download the full asset. Either an external URL or a /preview download endpoint (requires the same API key).",
            "nullable": true
          },
          "thumbnailUrl": {
            "type": "string",
            "description": "URL to a thumbnail rendition. Null if no thumbnail exists.",
            "nullable": true
          },
          "fileName": {
            "type": "string",
            "description": "Original file name, e.g. `widget-pro-front.jpg`.",
            "nullable": true
          },
          "displayName": {
            "type": "string",
            "description": "Display name for UI listings. Null if not set.",
            "nullable": true
          },
          "altText": {
            "type": "string",
            "description": "Alt text for images (SEO/accessibility). Null if not set.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Free-text description. Null if not set.",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "description": "MIME content type, e.g. `image/jpeg`, `application/pdf`.",
            "nullable": true
          },
          "fileSize": {
            "type": "integer",
            "description": "File size in bytes.",
            "format": "int64"
          },
          "width": {
            "type": "integer",
            "description": "Image width in pixels. Null for non-images or if unknown.",
            "format": "int32",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "description": "Image height in pixels. Null for non-images or if unknown.",
            "format": "int32",
            "nullable": true
          },
          "isPrimary": {
            "type": "boolean",
            "description": "Whether this is the item's primary image (used as thumbnail in item responses)."
          },
          "languageCode": {
            "type": "string",
            "description": "ISO 639-1 language code if the asset is language-specific, e.g. `sv`. Null if language-neutral.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order for galleries (ascending).",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "An image or document attached to an item."
      },
      "PublicItemAttribute": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable attribute code, e.g. `MATERIAL`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the attribute, e.g. `Material`.",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "The attribute value formatted as a string (numbers use invariant format, dates ISO 8601, booleans `true`/`false`).",
            "nullable": true
          },
          "dataType": {
            "$ref": "#/components/schemas/PublicAttributeDataType"
          },
          "unit": {
            "type": "string",
            "description": "Unit of the value, e.g. `mm`, `W`. Null if not applicable.",
            "nullable": true
          },
          "isVisibleOnWeb": {
            "type": "boolean",
            "description": "Whether the value is shown on the web — the item's own setting when it has one, otherwise the\nattribute's default. This is the flag the storefront filters on."
          },
          "groupCode": {
            "type": "string",
            "description": "Code of the attribute group it is shown under, e.g. `DIMENSIONS`. Null when ungrouped.",
            "nullable": true
          },
          "groupName": {
            "type": "string",
            "description": "Display name of the attribute group. Null when ungrouped.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The attribute's position in listings. Attributes are returned in this order.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A specification attribute value on an item."
      },
      "PublicItemAvailabilityResponse": {
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "description": "Item number of the item.",
            "nullable": true
          },
          "totalQuantityOnHand": {
            "type": "number",
            "description": "Total physical quantity on hand across all warehouses. Serialised as a decimal string.",
            "format": "double"
          },
          "totalAllocatedQuantity": {
            "type": "number",
            "description": "Total quantity reserved for orders across all warehouses. Serialised as a decimal string.",
            "format": "double"
          },
          "totalAvailableQuantity": {
            "type": "number",
            "description": "Total quantity available for new orders (on hand − allocated). Serialised as a decimal string.",
            "format": "double"
          },
          "warehouses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicWarehouseAvailability"
            },
            "description": "Per-warehouse breakdown. Empty list if the item is not stocked in any warehouse.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stock availability for an item, summed across warehouses and broken down per warehouse."
      },
      "PublicItemCategoryAssignment": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable category code, e.g. `TOOLS-HAND`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the category.",
            "nullable": true
          },
          "isPrimary": {
            "type": "boolean",
            "description": "Whether the category belongs to the primary category type (the main product hierarchy)."
          }
        },
        "additionalProperties": false,
        "description": "A category the item is assigned to."
      },
      "PublicItemChannelResponse": {
        "required": [
          "channelCode",
          "createdDate",
          "isActive",
          "isFeatured",
          "itemNumber",
          "showStock",
          "sortOrder"
        ],
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "description": "The published item.",
            "nullable": true
          },
          "channelCode": {
            "type": "string",
            "description": "The channel it is published on.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the publication is active. False hides the item without deleting the record."
          },
          "name": {
            "type": "string",
            "description": "Channel-specific name, or null to use the item's own.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Channel-specific long description, or null to use the item's own.",
            "nullable": true
          },
          "shortDescription": {
            "type": "string",
            "description": "Channel-specific short description, or null to use the item's own.",
            "nullable": true
          },
          "metaTitle": {
            "type": "string",
            "description": "SEO meta title for this channel, or null to fall back.",
            "nullable": true
          },
          "metaDescription": {
            "type": "string",
            "description": "SEO meta description for this channel, or null to fall back.",
            "nullable": true
          },
          "slug": {
            "type": "string",
            "description": "URL slug in this channel. Changing it creates a 301 redirect from the old one.",
            "nullable": true
          },
          "displayCategoryCode": {
            "type": "string",
            "description": "Code of the category the item is displayed under here, or null to use its primary category.",
            "nullable": true
          },
          "showStock": {
            "type": "boolean",
            "description": "Whether stock is shown for this item in this channel."
          },
          "stockDisplayMode": {
            "$ref": "#/components/schemas/PublicStockDisplayMode"
          },
          "allowBackorder": {
            "type": "boolean",
            "description": "Backorder override, or null to inherit from the item and then the channel.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order within the channel.",
            "format": "int32"
          },
          "isFeatured": {
            "type": "boolean",
            "description": "Whether the item is featured in this channel."
          },
          "publishDate": {
            "type": "string",
            "description": "When the item becomes visible, or null for immediately.",
            "format": "date-time",
            "nullable": true
          },
          "unpublishDate": {
            "type": "string",
            "description": "When the item stops being visible, or null for never.",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the publication was created (UTC).",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "When the publication was last changed (UTC), or null if never changed.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "One item's publication on one sales channel: whether it is published, and the channel-specific\ncontent that overrides the item's own."
      },
      "PublicItemConfigurationResponse": {
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "description": "Unique item number — business key, e.g. `CURTAIN-PLEAT`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name / product name.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Long-form description. Null if not set.",
            "nullable": true
          },
          "isConfigurable": {
            "type": "boolean",
            "description": "Whether the item has any configurable features at all. False means `features` is empty and the item is ordered as-is."
          },
          "baseUnitCode": {
            "type": "string",
            "description": "Code of the item's base unit of measure, e.g. `st`. The quantity on a configuration is expressed in this unit. Null if not set.",
            "nullable": true
          },
          "decimalPlaces": {
            "type": "integer",
            "description": "Number of decimals allowed on the quantity (0–6).",
            "format": "int32"
          },
          "salesPrice": {
            "type": "number",
            "description": "Default sales price per unit in the tenant base currency, before any configuration surcharge. Use POST /preview/configurations/calculate for the real, customer-specific price. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationFeature"
            },
            "description": "The configurable features, in the order they should be presented. Empty when the item is not configurable.",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "The configuration schema for an item, returned by GET /preview/items/{itemNumber}/configuration.\nEverything a configurator needs to render its form in one call: the fields, their types and\nbounds, the selectable options and what each choice does to the price.\n\nDeliberately not paginated. This is a resource, not a collection — a configurator cannot render a\nhalf-loaded form, so the whole schema always ships together (same treatment as `attributes`\non GET /preview/items/{itemNumber})."
      },
      "PublicItemCrossReference": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/PublicCrossReferenceType"
          },
          "referenceNumber": {
            "type": "string",
            "description": "The reference number/value.",
            "nullable": true
          },
          "source": {
            "type": "string",
            "description": "Source of the reference, e.g. a manufacturer or system name. Null if not set.",
            "nullable": true
          },
          "isPrimary": {
            "type": "boolean",
            "description": "Whether this is the preferred reference of its type."
          }
        },
        "additionalProperties": false,
        "description": "An alternative identifier for the item."
      },
      "PublicItemDetailResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "itemNumber": {
            "type": "string",
            "description": "Unique item number — business key, e.g. `WIDGET-PRO`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name / product name.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Long-form description, e.g. for a product page. Null if not set.",
            "nullable": true
          },
          "shortDescription": {
            "type": "string",
            "description": "Short selling description, e.g. for a product card. Null if not set.",
            "nullable": true
          },
          "slug": {
            "type": "string",
            "description": "URL slug for storefronts. Null when the item has none and the item number is used.",
            "nullable": true
          },
          "itemType": {
            "$ref": "#/components/schemas/PublicItemType"
          },
          "status": {
            "$ref": "#/components/schemas/PublicItemStatus"
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the item is active. Inactive items cannot be placed on new orders."
          },
          "isSellable": {
            "type": "boolean",
            "description": "Whether the item can be sold. False for component-only items."
          },
          "isStockable": {
            "type": "boolean",
            "description": "Whether the item is held in inventory. False for services, charges and drop-shipped items.\nDerived from `itemType` — use this rather than matching on the type yourself, so a new\nitem type does not silently change how your integration classifies the item."
          },
          "isConfigurable": {
            "type": "boolean",
            "description": "Whether the item is made to order from configurable features (measurements, fabrics, add-ons). True means GET /preview/items/{itemNumber}/configuration returns a configuration schema and the item is ordered through /preview/configurations rather than as a plain order line."
          },
          "publishOnWeb": {
            "type": "boolean",
            "description": "Whether the item has an active publication on at least one sales channel.\nRetained as a compatibility alias; new integrations should use channel publications."
          },
          "grade": {
            "$ref": "#/components/schemas/PublicGrade"
          },
          "defaultReplenishmentType": {
            "$ref": "#/components/schemas/PublicReplenishmentType"
          },
          "legacyItemNumber": {
            "type": "string",
            "description": "Item number in the system this item was migrated from. Null if not migrated.",
            "nullable": true
          },
          "decimalPlaces": {
            "type": "integer",
            "description": "Number of decimals allowed on quantities for this item (0–6). Quantities with more decimals are rejected.",
            "format": "int32"
          },
          "salesStartDate": {
            "type": "string",
            "description": "Date from which the item can be sold (ISO 8601 date). Null if unrestricted.",
            "format": "date",
            "nullable": true
          },
          "salesEndDate": {
            "type": "string",
            "description": "Date until which the item can be sold (ISO 8601 date). Null if unrestricted.",
            "format": "date",
            "nullable": true
          },
          "allowPreOrder": {
            "type": "boolean",
            "description": "Whether customers can pre-order the item before it is in stock."
          },
          "allowBackorder": {
            "type": "boolean",
            "description": "Whether customers can back-order the item when it is out of stock."
          },
          "baseUnitCode": {
            "type": "string",
            "description": "Code of the item's base unit of measure, e.g. `st`, `kg`. Null if not set.",
            "nullable": true
          },
          "barcode": {
            "type": "string",
            "description": "EAN / GTIN barcode of the base unit. Null if not set.",
            "nullable": true
          },
          "units": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemUnit"
            },
            "description": "All orderable units: the base unit first (factor 1), then alternative units (box, pallet, …) with their conversion factors and barcodes.",
            "nullable": true
          },
          "attributes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemAttribute"
            },
            "description": "Specification attributes (Material, Energy class, …) as name/value pairs. Empty if none.",
            "nullable": true
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemCategoryAssignment"
            },
            "description": "Category assignments for this item, each with its code, name and whether it belongs to the primary hierarchy. Empty if uncategorised.",
            "nullable": true
          },
          "crossReferences": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemCrossReference"
            },
            "description": "Alternative identifiers (manufacturer part numbers, OEM numbers, extra barcodes, …). Empty if none.",
            "nullable": true
          },
          "parentItemNumber": {
            "type": "string",
            "description": "Item number of the variant master this item belongs to. Null unless the item is a variant.",
            "nullable": true
          },
          "variantAttributes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemVariantAttribute"
            },
            "description": "The variant's own attribute values (e.g. Colour=Red, Size=M). Empty unless the item is a variant.",
            "nullable": true
          },
          "variantAxes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemVariantAxis"
            },
            "description": "The axes this variant master varies on, with the values available on each\n(e.g. Colour = [Red, Blue], Size = [S, M, L]). Empty unless the item is a variant master.\n\nThis is the master's side of the relationship — `variantAttributes` above is a single\nvariant's values. Use GET /preview/items/{itemNumber}/variants to enumerate the variants\nthemselves.",
            "nullable": true
          },
          "netWeight": {
            "type": "number",
            "description": "Net weight in kilograms. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "width": {
            "type": "number",
            "description": "Width in centimetres. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "height": {
            "type": "number",
            "description": "Height in centimetres. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "depth": {
            "type": "number",
            "description": "Depth in centimetres. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "volume": {
            "type": "number",
            "description": "Volume in <b>cubic metres</b>, computed from width × height × depth — which are in\n<b>centimetres</b>. Serialised as a decimal string. Null unless all three dimensions are set.",
            "format": "double",
            "nullable": true
          },
          "packages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemPackage"
            },
            "description": "The parcels one base unit of the item ships in, in parcel-number order — e.g. a sofa\nshipped as frame and cushions. Empty when the item has no parcel data, in which case\nfreight is estimated from `netWeight`.",
            "nullable": true
          },
          "grossWeight": {
            "type": "number",
            "description": "Gross weight in kilograms: the sum of the parcels' weights. Serialised as a decimal string.\nNull when the item has no parcels or any parcel lacks a weight — derived, not stored.",
            "format": "double",
            "nullable": true
          },
          "hsCode": {
            "type": "string",
            "description": "Harmonized System (HS / KN) customs tariff code. Null if not set.",
            "nullable": true
          },
          "countryOfOrigin": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country of manufacture, e.g. `SE`, `CN`. Null if not set.",
            "nullable": true
          },
          "salesPrice": {
            "type": "number",
            "description": "Default sales price in the tenant default currency. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "costPrice": {
            "type": "number",
            "description": "Purchase / cost price in the tenant default currency. Serialised as a decimal string.\nNull if not set.",
            "format": "double",
            "nullable": true
          },
          "costPriceMethod": {
            "$ref": "#/components/schemas/PublicCostPriceMethod"
          },
          "taxClassCode": {
            "type": "string",
            "description": "Code of the tax class governing VAT for this item, e.g. `STANDARD`. Null if not set,\nin which case the tenant default applies. Look the rate up via GET /preview/reference/tax-classes.",
            "nullable": true
          },
          "brandName": {
            "type": "string",
            "description": "Brand name. Null if not set.",
            "nullable": true
          },
          "brandCode": {
            "type": "string",
            "description": "Stable brand code, usable to correlate against your own brand register. Null if not set.",
            "nullable": true
          },
          "thumbnailUrl": {
            "type": "string",
            "description": "URL to the item's thumbnail image. Null if no image is set.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the item was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Full item details returned by GET /preview/items/{itemNumber}.\nContains everything needed to render a product page and create a valid order line:\nunits with barcodes, attributes, categories, cross-references and variant information.\nThe list endpoint (GET /preview/items) returns the leaner PublicApi.Preview.Items.Queries.PublicItemResponse."
      },
      "PublicItemFeatureType": {
        "enum": [
          "Text",
          "Number",
          "Selection",
          "Boolean",
          "ItemSelection",
          "Calculated"
        ],
        "type": "string",
        "description": "The kind of input a configurable feature takes, exposed via the Public API.\n\nMirrors `Domain.Items.ItemFeatureType` name-for-name and value-for-value so the two can be\ncast into each other. `PublicConfigurationEnumParityTests` fails the build if they ever drift\napart, which is what stops a new domain value from silently serialising as a bare number.\nThe cast must happen in memory, never in SQL — see PublicApi.Preview.Configurations.Queries.PublicItemFeatureTypeMapping.\nThe value determines which field to send on a configuration value: `text` for\nPublicApi.Preview.Configurations.Queries.PublicItemFeatureType.Text, `number` for PublicApi.Preview.Configurations.Queries.PublicItemFeatureType.Number, `optionCode` for\nPublicApi.Preview.Configurations.Queries.PublicItemFeatureType.Selection, `boolean` for PublicApi.Preview.Configurations.Queries.PublicItemFeatureType.Boolean and `itemNumber` for\nPublicApi.Preview.Configurations.Queries.PublicItemFeatureType.ItemSelection. PublicApi.Preview.Configurations.Queries.PublicItemFeatureType.Calculated takes no input at all."
      },
      "PublicItemImportance": {
        "enum": [
          "Critical",
          "Standard",
          "Accessory",
          "SpecialOrder"
        ],
        "type": "string",
        "description": "Stocking importance, which drives safety stock calculation.\nMirrors `Domain.Items.ItemImportance`."
      },
      "PublicItemPackage": {
        "type": "object",
        "properties": {
          "sequence": {
            "type": "integer",
            "description": "Parcel number on the item, 1..n — what reads as \"parcel 1/2\" on the delivery note.",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "What the parcel holds, e.g. `Frame`. Null if not set.",
            "nullable": true
          },
          "length": {
            "type": "number",
            "description": "Length in cm. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "width": {
            "type": "number",
            "description": "Width in cm. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "height": {
            "type": "number",
            "description": "Height in cm. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "grossWeight": {
            "type": "number",
            "description": "Gross weight in kg including packaging. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "barcode": {
            "type": "string",
            "description": "The parcel's own barcode (EAN), scanned at receiving and picking. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A parcel (kolli) one base unit of the item ships in."
      },
      "PublicItemPriceResponse": {
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "description": "Item number of the priced item.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the item.",
            "nullable": true
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number the price was calculated for. Null for the default price.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "Quantity the price was calculated for. Serialised as a decimal string.",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Calculated net unit price. Serialised as a decimal string.",
            "format": "double"
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code of the price.",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure code the price applies to, e.g. `st`.",
            "nullable": true
          },
          "priceSource": {
            "type": "string",
            "description": "Where the price came from, e.g. `Customer`, `Campaign`, `Standard`.",
            "nullable": true
          },
          "priceListName": {
            "type": "string",
            "description": "Name of the price list used. Null if no price list applied.",
            "nullable": true
          },
          "found": {
            "type": "boolean",
            "description": "Whether a price was found. If false, unitPrice is 0 and the item has no configured price."
          },
          "quantityBreaks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicQuantityBreak"
            },
            "description": "Volume price breaks from the applied price list. Empty if none.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Calculated price for an item, optionally customer-specific."
      },
      "PublicItemRelationDirection": {
        "enum": [
          "Outgoing",
          "Incoming"
        ],
        "type": "string",
        "description": "Which item a relation was set up on."
      },
      "PublicItemRelationResponse": {
        "type": "object",
        "properties": {
          "relatedItemNumber": {
            "type": "string",
            "description": "Item number of the item at the other end of the relation.",
            "nullable": true
          },
          "relatedItemName": {
            "type": "string",
            "description": "Name of the item at the other end of the relation.",
            "nullable": true
          },
          "relationType": {
            "$ref": "#/components/schemas/PublicItemRelationType"
          },
          "direction": {
            "$ref": "#/components/schemas/PublicItemRelationDirection"
          },
          "sortOrder": {
            "type": "integer",
            "description": "Position among the source item's relations of the same type (ascending).",
            "format": "int32"
          },
          "isBidirectional": {
            "type": "boolean",
            "description": "Whether the relation is also shown from the related item's side."
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A link from one item to another — an accessory, a spare part, a related product."
      },
      "PublicItemRelationType": {
        "enum": [
          "Related",
          "Accessory",
          "CrossSell",
          "UpSell",
          "SparePart",
          "GradedAlternative",
          "Replacement"
        ],
        "type": "string",
        "description": "Relation between two items. Mirrors `Domain.Items.ItemRelationType`."
      },
      "PublicItemResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "itemNumber": {
            "type": "string",
            "description": "Unique item number — business key, e.g. `WIDGET-PRO`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name / product name.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Long-form description, e.g. for a product page. Null if not set.",
            "nullable": true
          },
          "shortDescription": {
            "type": "string",
            "description": "Short selling description, e.g. for a product card. Null if not set.",
            "nullable": true
          },
          "slug": {
            "type": "string",
            "description": "URL slug for storefronts. Null when the item has none and the item number is used.",
            "nullable": true
          },
          "itemType": {
            "$ref": "#/components/schemas/PublicItemType"
          },
          "status": {
            "$ref": "#/components/schemas/PublicItemStatus"
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the item is active. Inactive items cannot be placed on new orders."
          },
          "isSellable": {
            "type": "boolean",
            "description": "Whether the item can be sold. False for component-only items."
          },
          "isStockable": {
            "type": "boolean",
            "description": "Whether the item is held in inventory. False for services, charges and drop-shipped items.\nDerived from `itemType` — use this rather than matching on the type yourself, so a new\nitem type does not silently change how your integration classifies the item."
          },
          "isConfigurable": {
            "type": "boolean",
            "description": "Whether the item is made to order from configurable features (measurements, fabrics, add-ons). True means GET /preview/items/{itemNumber}/configuration returns a configuration schema and the item is ordered through /preview/configurations rather than as a plain order line."
          },
          "publishOnWeb": {
            "type": "boolean",
            "description": "Whether the item has an active publication on at least one sales channel.\nRetained as a compatibility alias; new integrations should use channel publications."
          },
          "grade": {
            "$ref": "#/components/schemas/PublicGrade"
          },
          "decimalPlaces": {
            "type": "integer",
            "description": "Number of decimals allowed on quantities for this item (0–6). Quantities with more decimals are rejected.",
            "format": "int32"
          },
          "categoryName": {
            "type": "string",
            "description": "Name of the item's primary-hierarchy category. Null if not categorised.",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "Stable code of the item's primary-hierarchy category, e.g. `TOOLS-HAND` — the value to pass to `?categoryCode=` and the one a feature's `selectableItemCategoryCode` refers to. Null if not categorised.",
            "nullable": true
          },
          "salesStartDate": {
            "type": "string",
            "description": "Date from which the item can be sold (ISO 8601 date). Null if unrestricted.",
            "format": "date",
            "nullable": true
          },
          "salesEndDate": {
            "type": "string",
            "description": "Date until which the item can be sold (ISO 8601 date). Null if unrestricted.",
            "format": "date",
            "nullable": true
          },
          "parentItemNumber": {
            "type": "string",
            "description": "Item number of the variant master this item belongs to. Null unless the item is a variant.",
            "nullable": true
          },
          "baseUnitCode": {
            "type": "string",
            "description": "Code of the item's base unit of measure, e.g. `st`, `kg`. Null if not set.",
            "nullable": true
          },
          "barcode": {
            "type": "string",
            "description": "EAN / GTIN barcode or other scanning code. Null if not set.",
            "nullable": true
          },
          "netWeight": {
            "type": "number",
            "description": "Net weight in kilograms. Serialised as a decimal string to avoid IEEE 754 precision loss. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "width": {
            "type": "number",
            "description": "Width in centimetres. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "height": {
            "type": "number",
            "description": "Height in centimetres. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "depth": {
            "type": "number",
            "description": "Depth in centimetres. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "hsCode": {
            "type": "string",
            "description": "Harmonized System (HS / KN) customs tariff code. Null if not set.",
            "nullable": true
          },
          "countryOfOrigin": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country of manufacture, e.g. `SE`, `CN`. Null if not set.",
            "nullable": true
          },
          "salesPrice": {
            "type": "number",
            "description": "Default sales price in the tenant default currency. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "taxClassCode": {
            "type": "string",
            "description": "Code of the tax class governing VAT for this item, e.g. `STANDARD`. Null if not set,\nin which case the tenant default applies. Look the rate up via GET /preview/reference/tax-classes —\nthe rate depends on country and date and is therefore not a property of the item.",
            "nullable": true
          },
          "brandName": {
            "type": "string",
            "description": "Brand name. Null if not set.",
            "nullable": true
          },
          "brandCode": {
            "type": "string",
            "description": "Stable brand code, usable to correlate against your own brand register. Null if not set.",
            "nullable": true
          },
          "thumbnailUrl": {
            "type": "string",
            "description": "URL to the item's thumbnail image. Null if no image is set.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the item was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "matchedOn": {
            "type": "string",
            "description": "Which identifier the `?reference=` lookup matched on: `ItemNumber`, `Barcode`\n(the item's own), `PackBarcode` (a barcode on an alternative unit such as a box) or\n`CrossReference` (manufacturer/OEM number). Null unless `?reference=` was used.\n\nA scanner uses this to tell a single unit from a case: a `PackBarcode` match means the\nscanned code represents several base units, so read `units[]` on the item detail for\nthe conversion factor before booking a quantity.",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Item details returned by the list endpoint GET /preview/items.\n\nThe list carries what a delta sync needs to decide \"do I care about this row?\" plus what an\norder line needs to be valid. Anything requiring an extra join, an embedded collection or a\npricing/tax engine call lives on PublicApi.Preview.Items.Queries.PublicItemDetailResponse instead."
      },
      "PublicItemStatus": {
        "enum": [
          "Draft",
          "PendingApproval",
          "Active",
          "PhasingOut",
          "Discontinued",
          "Archived"
        ],
        "type": "string",
        "description": "Item status exposed via the Public API. Mirrors `Domain.Items.ItemStatus`."
      },
      "PublicItemTexts": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "shortDescription": {
            "type": "string",
            "nullable": true
          },
          "metaTitle": {
            "type": "string",
            "description": "Title for search engines.",
            "nullable": true
          },
          "metaDescription": {
            "type": "string",
            "description": "Description for search engines.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An item's texts: the item's own, or a translation of them."
      },
      "PublicItemTranslation": {
        "type": "object",
        "properties": {
          "languageCode": {
            "type": "string",
            "description": "ISO 639-1 code in lower case, e.g. `en`. The code to use in PUT .../translations/{languageCode}.",
            "nullable": true
          },
          "languageName": {
            "type": "string",
            "nullable": true
          },
          "texts": {
            "$ref": "#/components/schemas/PublicItemTexts"
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Fields the item has a text for but this language lacks: `name`, `description`,\n`shortDescription`, `metaTitle`, `metaDescription`. Empty when the language\nis complete. The language the item's own texts are written in shows every field as missing,\nsince it needs no translation.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An item's texts in one of the tenant's active languages."
      },
      "PublicItemTranslationsResponse": {
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "nullable": true
          },
          "base": {
            "$ref": "#/components/schemas/PublicItemTexts"
          },
          "languages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemTranslation"
            },
            "description": "One entry per active language, in the order the tenant has sorted them.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "GET /preview/items/{itemNumber}/translations."
      },
      "PublicItemType": {
        "enum": [
          "StockItem",
          "NonStockItem",
          "Service",
          "Work",
          "Consumable",
          "Kit",
          "Phantom",
          "Charge",
          "VariantMaster"
        ],
        "type": "string",
        "description": "Item type exposed via the Public API. Mirrors `Domain.Items.ItemType`."
      },
      "PublicItemUnit": {
        "type": "object",
        "properties": {
          "unitCode": {
            "type": "string",
            "description": "Unit code — usable as `unit` on order lines, e.g. `st`, `KART`.",
            "nullable": true
          },
          "conversionFactor": {
            "type": "number",
            "description": "How many base units this unit represents (1 KART = 12 st ⇒ 12). Serialised as a decimal string.",
            "format": "double"
          },
          "isSalesUnit": {
            "type": "boolean",
            "description": "Whether the unit may be used on sales order lines."
          },
          "isPurchaseUnit": {
            "type": "boolean",
            "description": "Whether the unit may be used on purchase order lines."
          },
          "barcode": {
            "type": "string",
            "description": "EAN / GTIN barcode for this specific unit/pack. Null if not set.",
            "nullable": true
          },
          "grossWeight": {
            "type": "number",
            "description": "Gross weight in kg of one whole unit including packaging. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "length": {
            "type": "number",
            "description": "Outer length in cm of one whole unit. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "width": {
            "type": "number",
            "description": "Outer width in cm of one whole unit. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "height": {
            "type": "number",
            "description": "Outer height in cm of one whole unit. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An orderable unit of measure for an item."
      },
      "PublicItemVariantAttribute": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Attribute name, e.g. `Colour`, `Size`.",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "The variant's value, e.g. `Red`, `M`.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A variant attribute value, e.g. Colour=Red."
      },
      "PublicItemVariantAxis": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Axis name, e.g. `Colour`, `Size`.",
            "nullable": true
          },
          "values": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The values defined for this axis, e.g. `Red`, `Blue`.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An axis a variant master varies on, with the values available along it."
      },
      "PublicItemVariantResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "itemNumber": {
            "type": "string",
            "description": "Unique item number of the variant — use this on order lines.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the variant.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicItemStatus"
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the variant is active. Inactive variants cannot be placed on new orders."
          },
          "isSellable": {
            "type": "boolean",
            "description": "Whether the variant can be sold."
          },
          "barcode": {
            "type": "string",
            "description": "EAN / GTIN barcode of the variant. Null if not set.",
            "nullable": true
          },
          "salesPrice": {
            "type": "number",
            "description": "Default sales price in the tenant default currency. Serialised as a decimal string. Null if not set.",
            "format": "double",
            "nullable": true
          },
          "thumbnailUrl": {
            "type": "string",
            "description": "URL to the variant's thumbnail image. Null if no public image is set.",
            "nullable": true
          },
          "variantAttributes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicItemVariantAttribute"
            },
            "description": "The values that distinguish this variant, e.g. Colour=Red, Size=M. One entry per axis\ndeclared by the master in `variantAxes`.",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "One variant belonging to a variant master, returned by\nGET /preview/items/{itemNumber}/variants.\n\nLean by design: it carries what a variant picker needs to render and what an order line needs\nto be valid. Fetch GET /preview/items/{itemNumber} for the full representation."
      },
      "PublicItemWarehouseResponse": {
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "description": "Item number — together with `warehouseCode` the address of this row.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the item.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Warehouse code — together with `itemNumber` the address of this row.",
            "nullable": true
          },
          "warehouseName": {
            "type": "string",
            "description": "Display name of the warehouse.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the item is active in this warehouse."
          },
          "minQuantity": {
            "type": "number",
            "description": "Reorder point. When projected stock falls below max(safetyStock, minQuantity), MRP proposes\nreplenishment according to `lotSizing`. Null if not set. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "maxQuantity": {
            "type": "number",
            "description": "Maximum stock level. The target for `FillToMax`. Null if not set. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "reorderQuantity": {
            "type": "number",
            "description": "Reorder quantity. The quantity ordered with `FixedReorderQuantity`. Null if not set.\nSerialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "safetyStock": {
            "type": "number",
            "description": "Safety stock set by hand. Null means MRP uses `calculatedSafetyStock`, or zero when that\nis null too. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "calculatedSafetyStock": {
            "type": "number",
            "description": "Read only. The safety stock Fluit last calculated from demand history, importance and service\nlevel. Used by MRP when `safetyStock` is null. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "leadTimeDays": {
            "type": "integer",
            "description": "Lead time in calendar days for this item in this warehouse. For a purchased item, the\nsupplier's lead time wins when one is set — see the endpoint description for the order.\nNull if not set.",
            "format": "int32",
            "nullable": true
          },
          "lotSizing": {
            "$ref": "#/components/schemas/PublicLotSizingPolicy"
          },
          "supplyPolicy": {
            "$ref": "#/components/schemas/PublicSupplyPolicy"
          },
          "replenishmentType": {
            "$ref": "#/components/schemas/PublicReplenishmentType"
          },
          "importance": {
            "$ref": "#/components/schemas/PublicItemImportance"
          },
          "serviceLevelOverride": {
            "type": "number",
            "description": "Service level between 0 and 1 (e.g. \"0.95\") that overrides the one implied by\n`importance`. Null if not overridden. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "transferFromWarehouseCode": {
            "type": "string",
            "description": "Warehouse the item is transferred from when `replenishmentType` is `Transfer`.\nNull means the warehouse's own transfer source applies.",
            "nullable": true
          },
          "transferLeadTimeDays": {
            "type": "integer",
            "description": "Transport time in days from the source warehouse. Null means the warehouse's own transport\ntime applies, when the source is the warehouse's.",
            "format": "int32",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "An item's stocking and replenishment settings in one warehouse, returned by\nGET /preview/item-warehouses and GET /preview/items/{itemNumber}/warehouses/{warehouseCode}.\n\nThese are the settings MRP plans with. Stock levels for the same row are read from\nGET /preview/items/{itemNumber}/availability."
      },
      "PublicLinks": {
        "type": "object",
        "properties": {
          "self": {
            "type": "string",
            "description": "Canonical URL of the resource, relative to the API base address.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Hypermedia links for a public API resource. Exposed as a computed `links` property on the\npublic response DTOs so that create and read responses carry the same self-reference — the\ncanonical URL is derived from the business key already present on the DTO and can never drift\nfrom the route it points at."
      },
      "PublicLogoSize": {
        "enum": [
          "Medium",
          "Small",
          "Large"
        ],
        "type": "string",
        "description": "How large the logos are drawn. Mirrors `Domain.Ecom.LogoSize`."
      },
      "PublicLotSizingPolicy": {
        "enum": [
          "LotForLot",
          "FixedReorderQuantity",
          "FillToMax"
        ],
        "type": "string",
        "description": "How much MRP proposes when a make-to-stock item needs replenishing in a warehouse.\nMirrors `Domain.Items.LotSizingPolicy`.\n\nThe policy reads the levels on the same item-warehouse row: `minQuantity` (the reorder\npoint), `reorderQuantity` and `maxQuantity`. A purchase quantity is then rounded up\nto the supplier's `minOrderQuantity` and `orderMultiple`."
      },
      "PublicMediaAspect": {
        "enum": [
          "Original",
          "Square",
          "Wide"
        ],
        "type": "string",
        "description": "The image's proportions in a MediaText section. Mirrors `Domain.Ecom.MediaAspect`."
      },
      "PublicMediaAssetResponse": {
        "required": [
          "channelCode",
          "contentType",
          "createdDate",
          "fileName",
          "fileSize",
          "folder",
          "folderId",
          "folderPath",
          "id",
          "url"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The file's identifier in the library. Its address on this API.",
            "format": "uuid"
          },
          "channelCode": {
            "type": "string",
            "description": "The channel the file belongs to.",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "The public URL the file is served on. This is what a page section references.",
            "nullable": true
          },
          "fileName": {
            "type": "string",
            "description": "The original file name it was uploaded under.",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "description": "MIME type, e.g. `image/webp`.",
            "nullable": true
          },
          "fileSize": {
            "type": "integer",
            "description": "File size in bytes.",
            "format": "int64"
          },
          "folder": {
            "$ref": "#/components/schemas/PublicChannelMediaFolder"
          },
          "folderId": {
            "type": "string",
            "description": "The folder the file sits in. Pass it as `folderId` to list or upload into it.",
            "format": "uuid"
          },
          "folderPath": {
            "type": "string",
            "description": "The folder's path from the top level, e.g. `Content/Products/Curtains`. A default folder\nthat has not been renamed is named after its role. Folders can be renamed and moved, so\naddress a folder by PublicApi.Preview.Media.Queries.PublicMediaAssetResponse.FolderId — the path is for display.",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Display name in the library, or null to fall back to the file name.",
            "nullable": true
          },
          "altText": {
            "type": "string",
            "description": "Alt text for accessibility, or null if the editor has not written one.",
            "nullable": true
          },
          "caption": {
            "type": "string",
            "description": "Caption, or null.",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "description": "Image width in pixels, or null when the dimensions were not read.",
            "format": "int32",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "description": "Image height in pixels, or null when the dimensions were not read.",
            "format": "int32",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the file was uploaded (UTC).",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "When its metadata was last changed (UTC), or null if never changed.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "One file in a channel's media library: the URL it is served on, plus the editorial metadata\naround it."
      },
      "PublicMediaPosition": {
        "enum": [
          "Left",
          "Right"
        ],
        "type": "string",
        "description": "Where the image stands in a MediaText section. Mirrors `Domain.Ecom.MediaPosition`."
      },
      "PublicOrderDetailResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "orderNumber": {
            "type": "string",
            "description": "Unique order number, e.g. `ORD-2024-00042`.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicSalesOrderStatus"
          },
          "deliveryStatus": {
            "$ref": "#/components/schemas/PublicDeliveryStatus"
          },
          "deliveredPercentage": {
            "type": "number",
            "description": "Share of the ordered quantity that has been delivered, 0-100. Serialised as a decimal string.",
            "format": "double"
          },
          "channelCode": {
            "type": "string",
            "description": "Code of the sales channel the order came in through: set by Fluit's webshop checkout and by\nchannel imports such as Shopify. Null for orders entered in Fluit or created through this API.\nUse it to tell webshop orders apart; the codes are listed by GET /preview/channels.",
            "nullable": true
          },
          "channelName": {
            "type": "string",
            "description": "Display name of the sales channel. Null when PublicApi.Preview.Orders.Queries.PublicOrderDetailResponse.ChannelCode is null.",
            "nullable": true
          },
          "externalOrderNumber": {
            "type": "string",
            "description": "The order's number in the system it was imported from, e.g. a marketplace or an older ERP.\nNull for orders that originate in Fluit.",
            "nullable": true
          },
          "externalOrderScope": {
            "type": "string",
            "description": "Which external system PublicApi.Preview.Orders.Queries.PublicOrderDetailResponse.ExternalOrderNumber belongs to, as free text set by the\nintegration, e.g. `Shopify`. Null when there is no external order number.",
            "nullable": true
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number of the buyer. Null if the order has no customer.",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "description": "Display name of the customer at the time of ordering. Null if not set.",
            "nullable": true
          },
          "customerReference": {
            "type": "string",
            "description": "Customer's own reference / purchase order number. Null if not provided.",
            "nullable": true
          },
          "orderDate": {
            "type": "string",
            "description": "Date the order was placed (ISO 8601 date).",
            "format": "date"
          },
          "requestedDeliveryDate": {
            "type": "string",
            "description": "Requested delivery date from the customer. Null if not provided.",
            "format": "date",
            "nullable": true
          },
          "plannedDeliveryDate": {
            "type": "string",
            "description": "Planned delivery date set by fulfilment. Null if not yet planned.",
            "format": "date",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code for all monetary values on this order.",
            "nullable": true
          },
          "paymentTermCode": {
            "type": "string",
            "description": "Payment term code, e.g. `NET30`. Null if not set.",
            "nullable": true
          },
          "paymentTermName": {
            "type": "string",
            "description": "Display name of the payment term. Null if not set.",
            "nullable": true
          },
          "deliveryTermCode": {
            "type": "string",
            "description": "Delivery / Incoterm code, e.g. `DAP`. Null if not set.",
            "nullable": true
          },
          "deliveryTermName": {
            "type": "string",
            "description": "Display name of the delivery term. Null if not set.",
            "nullable": true
          },
          "shippingMethodName": {
            "type": "string",
            "description": "Name of the shipping method / carrier. Null if not set.",
            "nullable": true
          },
          "deliveryAddress": {
            "$ref": "#/components/schemas/PublicDeliveryAddressResponse"
          },
          "externalNotes": {
            "type": "string",
            "description": "Free-text notes printed on order documents. Null if not set.",
            "nullable": true
          },
          "totalAmount": {
            "type": "number",
            "description": "Total order amount excluding tax, in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "totalVat": {
            "type": "number",
            "description": "Total VAT / tax amount, in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "totalAmountIncludingTax": {
            "type": "number",
            "description": "Total order amount including tax, in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicOrderLineResponse"
            },
            "description": "Order lines. Empty list if the order has no lines.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the order was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Full sales order details returned by GET /preview/orders/{id}.\nUses business-key codes (not Guids) for reference data like PaymentTerm and DeliveryTerm."
      },
      "PublicOrderLineResponse": {
        "type": "object",
        "properties": {
          "lineNumber": {
            "type": "integer",
            "description": "1-based sequential line number within the order.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number of the ordered item.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the ordered item at the time of ordering.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Customer-facing line text. Falls back to the item name when the line has no text of its own.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicOrderLineStatus"
          },
          "quantity": {
            "type": "number",
            "description": "Ordered quantity. Serialised as a decimal string.",
            "format": "double"
          },
          "deliveredQuantity": {
            "type": "number",
            "description": "Quantity already delivered / shipped. Serialised as a decimal string.",
            "format": "double"
          },
          "outstandingQuantity": {
            "type": "number",
            "description": "Remaining quantity not yet delivered (Quantity − DeliveredQuantity). Serialised as a decimal string.",
            "format": "double"
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure code, e.g. `st`, `kg`.",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Net unit price in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "discountPercent": {
            "type": "number",
            "description": "Line discount in percent (0–100). Serialised as a decimal string.",
            "format": "double"
          },
          "lineTotal": {
            "type": "number",
            "description": "Line total excluding tax (UnitPrice × Quantity × (1 − DiscountPercent / 100)). Serialised as a decimal string.",
            "format": "double"
          },
          "taxPercent": {
            "type": "number",
            "description": "Applicable tax / VAT rate in percent. Serialised as a decimal string.",
            "format": "double"
          },
          "lineTotalIncludingTax": {
            "type": "number",
            "description": "Line total including tax. Serialised as a decimal string.",
            "format": "double"
          },
          "notes": {
            "type": "string",
            "description": "Free-text line notes. Null if not set.",
            "nullable": true
          },
          "plannedDeliveryDate": {
            "type": "string",
            "description": "Planned delivery date for this specific line. Null if not yet set.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single order line returned as part of a sales order detail response."
      },
      "PublicOrderLineStatus": {
        "enum": [
          "Open",
          "Delivered",
          "Cancelled"
        ],
        "type": "string",
        "description": "Sales order line status values exposed via the Public API.\nDraft is intentionally omitted."
      },
      "PublicOrderListItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "orderNumber": {
            "type": "string",
            "description": "Unique order number, e.g. `ORD-2024-00042`.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicSalesOrderStatus"
          },
          "deliveryStatus": {
            "$ref": "#/components/schemas/PublicDeliveryStatus"
          },
          "deliveredPercentage": {
            "type": "number",
            "description": "Share of the ordered quantity that has been delivered, 0-100. Serialised as a decimal string.",
            "format": "double"
          },
          "channelCode": {
            "type": "string",
            "description": "Code of the sales channel the order came in through: set by Fluit's webshop checkout and by\nchannel imports such as Shopify. Null for orders entered in Fluit or created through this API.\nUse it to tell webshop orders apart; the codes are listed by GET /preview/channels.",
            "nullable": true
          },
          "channelName": {
            "type": "string",
            "description": "Display name of the sales channel. Null when PublicApi.Preview.Orders.Queries.PublicOrderListItem.ChannelCode is null.",
            "nullable": true
          },
          "externalOrderNumber": {
            "type": "string",
            "description": "The order's number in the system it was imported from, e.g. a marketplace or an older ERP.\nNull for orders that originate in Fluit.",
            "nullable": true
          },
          "externalOrderScope": {
            "type": "string",
            "description": "Which external system PublicApi.Preview.Orders.Queries.PublicOrderListItem.ExternalOrderNumber belongs to, as free text set by the\nintegration, e.g. `Shopify`. Null when there is no external order number.",
            "nullable": true
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number of the buyer. Null if the order has no customer.",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "description": "Display name of the customer. Null if not set.",
            "nullable": true
          },
          "customerReference": {
            "type": "string",
            "description": "Customer's own reference / purchase order number. Null if not provided.",
            "nullable": true
          },
          "orderDate": {
            "type": "string",
            "description": "Date the order was placed (ISO 8601 date).",
            "format": "date"
          },
          "requestedDeliveryDate": {
            "type": "string",
            "description": "Requested delivery date from the customer. Null if not provided.",
            "format": "date",
            "nullable": true
          },
          "plannedDeliveryDate": {
            "type": "string",
            "description": "Planned delivery date set by fulfilment. Null if not yet planned.",
            "format": "date",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code for all monetary values on this order.",
            "nullable": true
          },
          "totalAmount": {
            "type": "number",
            "description": "Total order amount excluding tax, in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "totalAmountIncludingTax": {
            "type": "number",
            "description": "Total order amount including tax, in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "lineCount": {
            "type": "integer",
            "description": "Number of order lines.",
            "format": "int32"
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the order was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Lightweight order summary returned by GET /preview/orders (list endpoint)."
      },
      "PublicOrderTypeResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code used as `orderTypeCode` in order creation.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the order type.",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the tenant's default order type."
          }
        },
        "additionalProperties": false,
        "description": "Order type available for sales order classification."
      },
      "PublicPageConfig": {
        "required": [
          "sections"
        ],
        "type": "object",
        "properties": {
          "layout": {
            "$ref": "#/components/schemas/PublicPageLayout"
          },
          "fullWidth": {
            "type": "boolean",
            "description": "True for a full-bleed page, false to keep the content inside the container width."
          },
          "sections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPageSection"
            },
            "description": "The sections, in the order they are rendered. Required on the way in — send `[]` to\nclear the page.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A page built from sections: the layout plus the sections in order."
      },
      "PublicPageLayout": {
        "enum": [
          "Standard",
          "WithSidebar",
          "Magazine"
        ],
        "type": "string",
        "description": "Page layout exposed via the Public API."
      },
      "PublicPageSection": {
        "required": [
          "type"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The section's own id, stable across edits so a client can address one section of a page.\nGenerated on create when omitted.",
            "format": "uuid",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/PublicPageSectionType"
          },
          "sortOrder": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Position on the page. Sections are rendered in ascending order.",
            "format": "int32"
          },
          "isVisible": {
            "type": "boolean",
            "description": "False hides the section without removing it."
          },
          "title": {
            "maxLength": 256,
            "type": "string",
            "description": "Section heading.",
            "nullable": true
          },
          "subtitle": {
            "maxLength": 500,
            "type": "string",
            "description": "Sub-heading or lead text.",
            "nullable": true
          },
          "cssClass": {
            "maxLength": 256,
            "type": "string",
            "description": "Extra CSS class, for storefronts that style sections themselves.",
            "nullable": true
          },
          "eyebrow": {
            "maxLength": 64,
            "type": "string",
            "description": "A short line above the heading (\"CONTACT\", \"OUR SERVICES\").",
            "nullable": true
          },
          "alignment": {
            "$ref": "#/components/schemas/PublicSectionAlignment"
          },
          "buttons": {
            "maxItems": 3,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSectionButton"
            },
            "description": "Buttons under the heading, at most three.",
            "nullable": true
          },
          "tone": {
            "$ref": "#/components/schemas/PublicSectionTone"
          },
          "spacing": {
            "$ref": "#/components/schemas/PublicSectionSpacing"
          },
          "anchor": {
            "maxLength": 64,
            "type": "string",
            "description": "HTML id, so a link can lead straight to the section (`/contact#write-to-us`).",
            "nullable": true
          },
          "heroImageUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "Background image for a Hero section.",
            "nullable": true
          },
          "heroCtaText": {
            "maxLength": 100,
            "type": "string",
            "description": "Call-to-action label.",
            "nullable": true
          },
          "heroCtaUrl": {
            "maxLength": 500,
            "type": "string",
            "description": "Where the call to action leads.",
            "nullable": true
          },
          "heroTextColor": {
            "$ref": "#/components/schemas/PublicHeroTextColor"
          },
          "heroVideoUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "Video played from the hero (YouTube, Vimeo or a direct link).",
            "nullable": true
          },
          "heroVideoPosterUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "Poster frame for a direct-link hero video. Falls back to heroImageUrl.",
            "nullable": true
          },
          "heroLayout": {
            "$ref": "#/components/schemas/PublicHeroLayout"
          },
          "heroHeight": {
            "$ref": "#/components/schemas/PublicHeroHeight"
          },
          "heroImageCaption": {
            "maxLength": 256,
            "type": "string",
            "description": "Short text laid over the image in a split hero.",
            "nullable": true
          },
          "heroPortraitUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "Portrait of the person the customer meets, drawn round below the buttons in a split hero.",
            "nullable": true
          },
          "heroPortraitText": {
            "maxLength": 256,
            "type": "string",
            "description": "The line beside the portrait.",
            "nullable": true
          },
          "itemGroupCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Item group to take products from, by category code.",
            "nullable": true
          },
          "categoryCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Category to take products from, by category code.",
            "nullable": true
          },
          "productNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Manually picked products, by item number, in display order.",
            "nullable": true
          },
          "maxProducts": {
            "maximum": 50,
            "minimum": 1,
            "type": "integer",
            "description": "How many products to show at most.",
            "format": "int32"
          },
          "productSort": {
            "$ref": "#/components/schemas/PublicProductSortOrder"
          },
          "productColumns": {
            "maximum": 6,
            "minimum": 1,
            "type": "integer",
            "description": "Columns in the product grid.",
            "format": "int32"
          },
          "categoryCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Specific categories to show, by category code.",
            "nullable": true
          },
          "parentCategoryCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Show every child of this category, by category code.",
            "nullable": true
          },
          "categoryLayout": {
            "$ref": "#/components/schemas/PublicCategoryLayout"
          },
          "categoryImageAspect": {
            "$ref": "#/components/schemas/PublicCategoryImageAspect"
          },
          "categoryColumns": {
            "maximum": 6,
            "minimum": 0,
            "type": "integer",
            "description": "Columns on wide screens: 0 lets the storefront choose, otherwise 2–6 (1 is rejected).\nNarrower screens get fewer.",
            "format": "int32"
          },
          "showProductCount": {
            "type": "boolean",
            "description": "Show the number of products under each category's name."
          },
          "bannerImageUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "Banner image.",
            "nullable": true
          },
          "bannerLinkUrl": {
            "maxLength": 500,
            "type": "string",
            "description": "Where the banner leads.",
            "nullable": true
          },
          "bannerStartDate": {
            "type": "string",
            "description": "When the banner starts showing. Null means immediately.",
            "format": "date-time",
            "nullable": true
          },
          "bannerEndDate": {
            "type": "string",
            "description": "When the banner stops showing. Null means never.",
            "format": "date-time",
            "nullable": true
          },
          "htmlContent": {
            "maxLength": 50000,
            "type": "string",
            "description": "HTML body for a TextBlock section.",
            "nullable": true
          },
          "lead": {
            "maxLength": 1000,
            "type": "string",
            "description": "Lead paragraph of a TextBlock section, between heading and body.",
            "nullable": true
          },
          "twoColumns": {
            "type": "boolean",
            "description": "Break the TextBlock body into two columns on wide screens."
          },
          "narrowText": {
            "type": "boolean",
            "description": "A narrow text column, for long reads."
          },
          "supplierNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Specific suppliers to show, by supplier number.",
            "nullable": true
          },
          "maxBrands": {
            "maximum": 50,
            "minimum": 1,
            "type": "integer",
            "description": "How many brands to show at most.",
            "format": "int32"
          },
          "videoUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "Video URL (YouTube, Vimeo or a direct mp4 link).",
            "nullable": true
          },
          "galleryImages": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPageSectionImage"
            },
            "description": "Images in a gallery or carousel section.",
            "nullable": true
          },
          "testimonials": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPageSectionTestimonial"
            },
            "description": "Testimonials to show.",
            "nullable": true
          },
          "featureCards": {
            "maxItems": 12,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPageSectionFeatureCard"
            },
            "description": "Cards in a FeatureCards section.",
            "nullable": true
          },
          "cardVariant": {
            "$ref": "#/components/schemas/PublicCardVariant"
          },
          "cardColumns": {
            "maximum": 4,
            "minimum": 0,
            "type": "integer",
            "description": "Columns on wide screens (2–4). Zero lets the storefront choose from the number of cards.",
            "format": "int32"
          },
          "form": {
            "$ref": "#/components/schemas/PublicSectionForm"
          },
          "mediaText": {
            "$ref": "#/components/schemas/PublicSectionMediaText"
          },
          "faq": {
            "$ref": "#/components/schemas/PublicSectionFaq"
          },
          "logos": {
            "$ref": "#/components/schemas/PublicSectionLogos"
          },
          "timeline": {
            "$ref": "#/components/schemas/PublicSectionTimeline"
          },
          "contact": {
            "$ref": "#/components/schemas/PublicSectionContact"
          },
          "sectionCollectionId": {
            "type": "string",
            "description": "A SharedSections section's collection. An opaque id: read it from a page and send it back\nunchanged; collections are managed in Fluit. Required on a SharedSections section — omit it\nor send an empty id and the write is rejected with 400 naming\nsections[{index}].sectionCollectionId. Ignored on every other section type.",
            "format": "uuid",
            "nullable": true
          },
          "custom": {
            "$ref": "#/components/schemas/PublicSectionCustom"
          },
          "productSpotlight": {
            "$ref": "#/components/schemas/PublicSectionProductSpotlight"
          },
          "embed": {
            "$ref": "#/components/schemas/PublicSectionEmbed"
          },
          "articleType": {
            "$ref": "#/components/schemas/PublicArticleSourceType"
          },
          "articleLinkText": {
            "maxLength": 100,
            "type": "string",
            "description": "Label on the link to the archive. Empty hides the link.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One section on a page. Which fields apply depends on PublicApi.Preview.ContentPages.Queries.PublicPageSection.Type; the rest are ignored."
      },
      "PublicPageSectionFeatureCard": {
        "required": [
          "title"
        ],
        "type": "object",
        "properties": {
          "iconName": {
            "maxLength": 64,
            "type": "string",
            "description": "Icon from the storefront's fixed set, e.g. `shield` or `truck`.\nAn unknown name draws no icon rather than failing.",
            "nullable": true
          },
          "title": {
            "maxLength": 128,
            "minLength": 1,
            "type": "string",
            "description": "Card heading."
          },
          "text": {
            "maxLength": 500,
            "type": "string",
            "description": "Body text under the heading.",
            "nullable": true
          },
          "linkUrl": {
            "maxLength": 500,
            "type": "string",
            "description": "Where the card links. Null makes it non-clickable. Either a storefront path starting with\n`/` or an absolute http(s) URL — a protocol-relative address is refused, because it\ninherits the page's scheme while looking like an internal path.",
            "nullable": true
          },
          "linkText": {
            "maxLength": 100,
            "type": "string",
            "description": "Link label. Without one the whole card is clickable.",
            "nullable": true
          },
          "imageUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "The card's image, when the section draws cards with images.",
            "nullable": true
          },
          "imageAlt": {
            "maxLength": 256,
            "type": "string",
            "description": "Alt text for the card's image.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One card in a FeatureCards section."
      },
      "PublicPageSectionImage": {
        "required": [
          "imageUrl"
        ],
        "type": "object",
        "properties": {
          "imageUrl": {
            "maxLength": 2048,
            "minLength": 1,
            "type": "string",
            "description": "The image."
          },
          "linkUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "Where the image links. Null makes it non-clickable.",
            "nullable": true
          },
          "caption": {
            "maxLength": 256,
            "type": "string",
            "description": "Caption shown with the image.",
            "nullable": true
          },
          "altText": {
            "maxLength": 256,
            "type": "string",
            "description": "Alt text, for accessibility.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One image in a gallery section."
      },
      "PublicPageSectionTestimonial": {
        "required": [
          "quote"
        ],
        "type": "object",
        "properties": {
          "quote": {
            "maxLength": 2000,
            "minLength": 1,
            "type": "string",
            "description": "The quote itself."
          },
          "author": {
            "maxLength": 128,
            "type": "string",
            "description": "Who said it.",
            "nullable": true
          },
          "role": {
            "maxLength": 128,
            "type": "string",
            "description": "Their role or company.",
            "nullable": true
          },
          "rating": {
            "maximum": 5,
            "minimum": 1,
            "type": "integer",
            "description": "Rating from 1 to 5. Null shows no rating.",
            "format": "int32",
            "nullable": true
          },
          "avatarUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "Portrait image.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One testimonial."
      },
      "PublicPageSectionType": {
        "enum": [
          "Hero",
          "FeaturedProducts",
          "ProductsByCategory",
          "ProductsByGroup",
          "NewArrivals",
          "BestSellers",
          "OnSale",
          "Categories",
          "Banner",
          "TextBlock",
          "Newsletter",
          "Brands",
          "Testimonials",
          "ImageGallery",
          "Video",
          "Divider",
          "LatestArticles",
          "FeatureCards",
          "CallToAction",
          "Form",
          "MediaText",
          "Faq",
          "Logos",
          "Contact",
          "SharedSections",
          "Custom",
          "Timeline",
          "ProductSpotlight",
          "Embed"
        ],
        "type": "string",
        "description": "The kinds of section a page can be built from.\nMirrors `Domain.Ecom.PageSectionType` — see PublicApi.Preview.ContentPages.Queries.PublicPageLayout for why."
      },
      "PublicPaymentTermResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code used as `paymentTermCode` in order creation.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the payment term.",
            "nullable": true
          },
          "days": {
            "type": "integer",
            "description": "Number of net payment days. Null if not applicable.",
            "format": "int32",
            "nullable": true
          },
          "isDefaultSales": {
            "type": "boolean",
            "description": "Whether this is the default payment term for new sales orders."
          }
        },
        "additionalProperties": false,
        "description": "Payment term available on sales orders and customers."
      },
      "PublicPriceListLineResponse": {
        "type": "object",
        "properties": {
          "itemNumber": {
            "type": "string",
            "description": "Item number of the priced item.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Name of the priced item.",
            "nullable": true
          },
          "strategy": {
            "$ref": "#/components/schemas/PublicPricingStrategy"
          },
          "unitPrice": {
            "type": "number",
            "description": "The price that applies, in the list's currency. For a fixed price it is the price as entered.\nFor a calculated line it is the most recently calculated price, or null when the line has\nnot been calculated yet. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "calculatedAt": {
            "type": "string",
            "description": "When a calculated line's price was last calculated. Null on a fixed price.",
            "format": "date-time",
            "nullable": true
          },
          "percentage": {
            "type": "number",
            "description": "Percentage used by the calculated strategies (markup or discount). Null on a fixed price.\nSerialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "fixedAmount": {
            "type": "number",
            "description": "Amount added to the cost price by `CostPlusAmount`. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "minQuantity": {
            "type": "number",
            "description": "The price applies from this quantity. 0 means from the first unit. Part of the line's key\ntogether with itemNumber and validFrom. Serialised as a decimal string.",
            "format": "double"
          },
          "maxQuantity": {
            "type": "number",
            "description": "The price applies up to and including this quantity. Null when there is no upper limit.",
            "format": "double",
            "nullable": true
          },
          "validFrom": {
            "type": "string",
            "description": "First day the price applies. Null when it has no start date. Part of the line's key.",
            "format": "date",
            "nullable": true
          },
          "validTo": {
            "type": "string",
            "description": "Last day the price applies. Null when it has no end date.",
            "format": "date",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "One price in a price list: an item's price from a quantity and a date."
      },
      "PublicPriceListResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The price list's code. Addresses it in /preview/price-lists/{code}/lines.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name, e.g. `Gross SEK`.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Free-text description.",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/PublicPriceListType"
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code of every price in the list.",
            "nullable": true
          },
          "isPriceIncludingTax": {
            "type": "boolean",
            "description": "Whether the prices include VAT."
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the list is in use. An inactive list is never applied to an order."
          },
          "validFrom": {
            "type": "string",
            "description": "First day the list applies. Null when it has no start date.",
            "format": "date",
            "nullable": true
          },
          "validTo": {
            "type": "string",
            "description": "Last day the list applies. Null when it has no end date.",
            "format": "date",
            "nullable": true
          },
          "priority": {
            "type": "integer",
            "description": "Priority when several lists apply to the same customer; the lower number wins.",
            "format": "int32"
          },
          "basePriceListCode": {
            "type": "string",
            "description": "Code of the list this one derives prices from, for lines with the strategy\n`ParentPriceList`. Null when it has none.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A price list — the prices one set of customers pays, in one currency."
      },
      "PublicPriceListType": {
        "enum": [
          "Standard",
          "Customer",
          "CustomerGroup",
          "Campaign",
          "Contract"
        ],
        "type": "string",
        "description": "What a price list is for. Mirrors the domain values name for name."
      },
      "PublicPricingStrategy": {
        "enum": [
          "Fixed",
          "CostPlusPercent",
          "CostPlusAmount",
          "BasePriceDiscount",
          "ParentPriceList"
        ],
        "type": "string",
        "description": "How a price list line gets its price. Mirrors the domain values name for name."
      },
      "PublicProductSortOrder": {
        "enum": [
          "Manual",
          "Newest",
          "PriceLowToHigh",
          "PriceHighToLow",
          "Bestselling",
          "Random",
          "Alphabetical"
        ],
        "type": "string",
        "description": "How products are ordered inside a product section.\nMirrors `Domain.Ecom.ProductSortOrder`."
      },
      "PublicPurchaseDeliveryAddressResponse": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Recipient company or person name.",
            "nullable": true
          },
          "street1": {
            "type": "string",
            "description": "Street address line 1.",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "description": "Postal / ZIP code.",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "City name.",
            "nullable": true
          },
          "countryCode": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`.",
            "nullable": true
          },
          "street2": {
            "type": "string",
            "description": "Street address line 2 (c/o, suite, etc.). Null if not set.",
            "nullable": true
          },
          "contactPerson": {
            "type": "string",
            "description": "Contact person at the delivery address. Null if not set.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Phone number at the delivery address. Null if not set.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address at the delivery address. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Delivery address attached to a purchase order."
      },
      "PublicPurchaseOrderLineResponse": {
        "type": "object",
        "properties": {
          "lineNumber": {
            "type": "integer",
            "description": "1-based sequential line number within the order — the business key used in line URLs.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number of the ordered item.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the ordered item.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicPurchaseOrderLineStatus"
          },
          "quantity": {
            "type": "number",
            "description": "Ordered quantity. Serialised as a decimal string.",
            "format": "double"
          },
          "receivedQuantity": {
            "type": "number",
            "description": "Quantity already received into stock. Serialised as a decimal string.",
            "format": "double"
          },
          "outstandingQuantity": {
            "type": "number",
            "description": "Remaining quantity not yet received (Quantity − ReceivedQuantity). Serialised as a decimal string.",
            "format": "double"
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure code, e.g. `st`, `kg`.",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Purchase price per unit in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "lineTotal": {
            "type": "number",
            "description": "Line total excluding tax (UnitPrice × Quantity). Serialised as a decimal string.",
            "format": "double"
          },
          "expectedDate": {
            "type": "string",
            "description": "Expected delivery date for this line (ISO 8601 date). Null if not set.",
            "format": "date",
            "nullable": true
          },
          "promisedDeliveryDate": {
            "type": "string",
            "description": "Delivery date promised by the supplier for this line. Null until confirmed.",
            "format": "date",
            "nullable": true
          },
          "confirmedQuantity": {
            "type": "number",
            "description": "Quantity confirmed by the supplier. Null until confirmed. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "confirmedUnitPrice": {
            "type": "number",
            "description": "Unit price confirmed by the supplier. Null until confirmed. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "confirmedDeliveryDate": {
            "type": "string",
            "description": "Delivery date confirmed by the supplier. Null until confirmed.",
            "format": "date",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text line notes. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single purchase order line."
      },
      "PublicPurchaseOrderLineStatus": {
        "enum": [
          "Ordered",
          "Confirmed",
          "ConfirmedWithDeviations",
          "PartiallyReceived",
          "Received",
          "Cancelled"
        ],
        "type": "string",
        "description": "Purchase order line status values exposed via the Public API.\nMirrors `Domain.Common.Enums.PurchaseOrderLineStatus` — see PublicApi.Preview.Purchasing.Queries.PublicPurchaseOrderStatus."
      },
      "PublicPurchaseOrderListItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "orderNumber": {
            "type": "string",
            "description": "Unique purchase order number, e.g. `PO-2026-00042`.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicPurchaseOrderStatus"
          },
          "supplierNumber": {
            "type": "string",
            "description": "Supplier number of the seller.",
            "nullable": true
          },
          "supplierName": {
            "type": "string",
            "description": "Display name of the supplier.",
            "nullable": true
          },
          "supplierReference": {
            "type": "string",
            "description": "The supplier's own order reference. Null if not provided.",
            "nullable": true
          },
          "orderDate": {
            "type": "string",
            "description": "Date the order was placed (ISO 8601 date).",
            "format": "date"
          },
          "expectedDeliveryDate": {
            "type": "string",
            "description": "Date we expect the goods to arrive. Null if not set.",
            "format": "date",
            "nullable": true
          },
          "promisedDeliveryDate": {
            "type": "string",
            "description": "Delivery date promised by the supplier. Null until confirmed.",
            "format": "date",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Code of the warehouse the goods are received into.",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code for all monetary values on this order.",
            "nullable": true
          },
          "totalAmount": {
            "type": "number",
            "description": "Total order amount excluding tax, in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "lineCount": {
            "type": "integer",
            "description": "Number of purchase order lines.",
            "format": "int32"
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the order was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Lightweight purchase order summary returned by GET /preview/purchase-orders (list endpoint)."
      },
      "PublicPurchaseOrderResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "orderNumber": {
            "type": "string",
            "description": "Unique purchase order number, e.g. `PO-2026-00042`.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicPurchaseOrderStatus"
          },
          "supplierNumber": {
            "type": "string",
            "description": "Supplier number of the seller.",
            "nullable": true
          },
          "supplierName": {
            "type": "string",
            "description": "Display name of the supplier.",
            "nullable": true
          },
          "supplierReference": {
            "type": "string",
            "description": "The supplier's own order reference / confirmation number. Null if not provided.",
            "nullable": true
          },
          "orderDate": {
            "type": "string",
            "description": "Date the order was placed (ISO 8601 date).",
            "format": "date"
          },
          "expectedDeliveryDate": {
            "type": "string",
            "description": "Date we expect the goods to arrive. Null if not set.",
            "format": "date",
            "nullable": true
          },
          "promisedDeliveryDate": {
            "type": "string",
            "description": "Delivery date promised by the supplier. Null until confirmed.",
            "format": "date",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Code of the warehouse the goods are received into.",
            "nullable": true
          },
          "warehouseName": {
            "type": "string",
            "description": "Display name of the receiving warehouse.",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code for all monetary values on this order.",
            "nullable": true
          },
          "paymentTermCode": {
            "type": "string",
            "description": "Payment term code, e.g. `NET30`. Null if not set.",
            "nullable": true
          },
          "paymentTermName": {
            "type": "string",
            "description": "Display name of the payment term. Null if not set.",
            "nullable": true
          },
          "deliveryTermCode": {
            "type": "string",
            "description": "Delivery / Incoterm code, e.g. `DAP`. Null if not set.",
            "nullable": true
          },
          "deliveryTermName": {
            "type": "string",
            "description": "Display name of the delivery term. Null if not set.",
            "nullable": true
          },
          "shippingMethodCode": {
            "type": "string",
            "description": "Shipping method / carrier code. Null if not set.",
            "nullable": true
          },
          "shippingMethodName": {
            "type": "string",
            "description": "Display name of the shipping method. Null if not set.",
            "nullable": true
          },
          "deliveryAddress": {
            "$ref": "#/components/schemas/PublicPurchaseDeliveryAddressResponse"
          },
          "isDropShipment": {
            "type": "boolean",
            "description": "Whether the goods ship directly from the supplier to an end customer."
          },
          "externalNotes": {
            "type": "string",
            "description": "Free-text notes printed on the purchase order document. Null if not set.",
            "nullable": true
          },
          "totalAmount": {
            "type": "number",
            "description": "Total order amount excluding tax, in the order currency. Serialised as a decimal string.",
            "format": "double"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPurchaseOrderLineResponse"
            },
            "description": "Purchase order lines. Empty list if the order has no lines.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the order was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Full purchase order details returned by GET /preview/purchase-orders/{orderNumber}.\nUses business-key codes (not Guids) for reference data like Supplier, Warehouse and PaymentTerm."
      },
      "PublicPurchaseOrderStatus": {
        "enum": [
          "Draft",
          "Sent",
          "PartiallyConfirmed",
          "Confirmed",
          "PartiallyReceived",
          "Received",
          "Closed",
          "Cancelled"
        ],
        "type": "string",
        "description": "Purchase order status values exposed via the Public API.\n\nMirrors `Domain.Common.Enums.PurchaseOrderStatus` name-for-name and value-for-value so the\nquery projections can cast directly — a cast is translatable to SQL where a switch over a helper\nmethod is not. `PublicPurchaseEnumParityTests` fails the build if the two ever drift apart,\nwhich is what stops a new domain value from silently serialising as a bare number.\nUnlike sales orders, `Draft`<b>is</b> part of the public contract: a purchase order created\nthrough POST /preview/purchase-orders starts in Draft, and the caller has to be able to read back\nthe order it just created before sending it."
      },
      "PublicQuantityBreak": {
        "type": "object",
        "properties": {
          "minQuantity": {
            "type": "number",
            "description": "Minimum quantity for this price. Serialised as a decimal string.",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Unit price at this quantity. Serialised as a decimal string.",
            "format": "double"
          },
          "discountPercent": {
            "type": "number",
            "description": "Discount in percent compared to the base price. Serialised as a decimal string. Null if not applicable.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Volume price break — the unit price that applies from a minimum quantity."
      },
      "PublicQuoteLineResponse": {
        "type": "object",
        "properties": {
          "lineNumber": {
            "type": "integer",
            "description": "Line number, unique within the quote.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number. Null on a free-text line — quotes created through this API always carry an\nitem, but quotes written inside the ERP may have lines that are pure text.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Line description as it appears on the quote.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "Quantity. Serialised as a decimal string.",
            "format": "double"
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure code. Null if not set.",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Net unit price in the quote currency. Serialised as a decimal string.",
            "format": "double"
          },
          "discountPercent": {
            "type": "number",
            "description": "Line discount in percent. Serialised as a decimal string.",
            "format": "double"
          },
          "lineTotal": {
            "type": "number",
            "description": "Line total excluding VAT, after discount. Serialised as a decimal string.",
            "format": "double"
          },
          "taxPercent": {
            "type": "number",
            "description": "VAT rate applied to the line, in percent. Serialised as a decimal string.",
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "A line on a sales quote."
      },
      "PublicQuoteResponse": {
        "type": "object",
        "properties": {
          "quoteNumber": {
            "type": "string",
            "description": "Unique quote number.",
            "nullable": true
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number the quote is addressed to. Null for a prospect that has not been given\none yet — quoting a prospect is the point of a pipeline, so the field is not guaranteed.",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "description": "Customer name at the time of reading.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicQuoteStatus"
          },
          "title": {
            "type": "string",
            "description": "Short title. Null if not set.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Longer description. Null if not set.",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code the quote is priced in.",
            "nullable": true
          },
          "quoteDate": {
            "type": "string",
            "description": "Quote date (ISO 8601 date).",
            "format": "date"
          },
          "validUntil": {
            "type": "string",
            "description": "Last date the quote is valid (ISO 8601 date).",
            "format": "date"
          },
          "sentAt": {
            "type": "string",
            "description": "UTC timestamp when the quote was sent. Null while Draft.",
            "format": "date-time",
            "nullable": true
          },
          "acceptedAt": {
            "type": "string",
            "description": "UTC timestamp when the customer accepted. Null unless accepted.",
            "format": "date-time",
            "nullable": true
          },
          "declinedAt": {
            "type": "string",
            "description": "UTC timestamp when the customer declined. Null unless declined.",
            "format": "date-time",
            "nullable": true
          },
          "declinedReason": {
            "type": "string",
            "description": "Reason given for declining. Null unless declined with a reason.",
            "nullable": true
          },
          "convertedToOrderNumber": {
            "type": "string",
            "description": "Order number the quote was converted into. Null until converted.",
            "nullable": true
          },
          "totalAmount": {
            "type": "number",
            "description": "Net total in the quote currency. Serialised as a decimal string.",
            "format": "double"
          },
          "totalVat": {
            "type": "number",
            "description": "Total VAT in the quote currency. Serialised as a decimal string.",
            "format": "double"
          },
          "totalAmountIncludingTax": {
            "type": "number",
            "description": "Gross total in the quote currency. Serialised as a decimal string.",
            "format": "double"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicQuoteLineResponse"
            },
            "description": "The quote's lines.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the quote was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp when the quote was last modified. Null if never modified.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A sales quote."
      },
      "PublicQuoteStatus": {
        "enum": [
          "Draft",
          "Sent",
          "Accepted",
          "Declined",
          "Expired",
          "Converted"
        ],
        "type": "string",
        "description": "Status of a sales quote."
      },
      "PublicReceiptLineResponse": {
        "type": "object",
        "properties": {
          "lineNumber": {
            "type": "integer",
            "description": "Line number, unique within the receipt.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number received.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the item.",
            "nullable": true
          },
          "locationCode": {
            "type": "string",
            "description": "Location the goods were put into.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "Quantity received. Serialised as a decimal string.",
            "format": "double"
          },
          "unitCost": {
            "type": "number",
            "description": "Unit cost booked, in the tenant's base currency. Serialised as a decimal string.",
            "format": "double"
          },
          "purchaseOrderNumber": {
            "type": "string",
            "description": "Purchase order number this line received against. Null for transfer receipts.",
            "nullable": true
          },
          "transferOrderNumber": {
            "type": "string",
            "description": "Transfer order number this line received against. Null for purchase receipts.",
            "nullable": true
          },
          "serialNumber": {
            "type": "string",
            "description": "Serial number, for serial-tracked items.",
            "nullable": true
          },
          "batchNumber": {
            "type": "string",
            "description": "Batch / lot number, for batch-tracked items.",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text notes on the line. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A line on a goods receipt."
      },
      "PublicReceiptResponse": {
        "type": "object",
        "properties": {
          "receiptNumber": {
            "type": "string",
            "description": "Unique receipt number.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Warehouse the goods arrived at.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicReceiptStatus"
          },
          "receiptDate": {
            "type": "string",
            "description": "UTC timestamp of the receipt.",
            "format": "date-time"
          },
          "notes": {
            "type": "string",
            "description": "Free-text notes. Null if not set.",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReceiptLineResponse"
            },
            "description": "The receipt's lines.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the receipt was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp when the receipt was last modified. Null if never modified.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A goods receipt — what physically arrived at a warehouse."
      },
      "PublicReceiptStatus": {
        "enum": [
          "Draft",
          "InProgress",
          "Completed",
          "Cancelled"
        ],
        "type": "string",
        "description": "Status of a goods receipt."
      },
      "PublicRedirectResponse": {
        "required": [
          "channelCode",
          "fromPath",
          "toPath"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable id of the redirect. Use it to update or delete it.",
            "format": "uuid"
          },
          "channelCode": {
            "type": "string",
            "description": "Code of the channel the redirect belongs to.",
            "nullable": true
          },
          "fromPath": {
            "type": "string",
            "description": "The old path that is redirected, normalized to lowercase with a leading slash and no\ntrailing slash, e.g. `/old-product`. Unique within the channel.",
            "nullable": true
          },
          "toPath": {
            "type": "string",
            "description": "Where the visitor is sent: a path starting with `/` or an absolute http(s) URL.",
            "nullable": true
          },
          "statusCode": {
            "type": "integer",
            "description": "HTTP status code of the redirect: 301 (permanent) or 302 (temporary).",
            "format": "int32"
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the storefront applies the redirect."
          },
          "hitCount": {
            "type": "integer",
            "description": "Number of times a visitor has followed the redirect.",
            "format": "int32"
          },
          "lastHitAt": {
            "type": "string",
            "description": "When a visitor last followed the redirect, or null if never.",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A URL redirect in a channel's web shop, as the public API exposes it."
      },
      "PublicReplenishmentType": {
        "enum": [
          "Purchase",
          "Manufacture",
          "Transfer",
          "Assembly",
          "Subcontract"
        ],
        "type": "string",
        "description": "How an item is replenished. Mirrors `Domain.Items.ReplenishmentType`.\nCan be overridden per warehouse."
      },
      "PublicReturnLineResponse": {
        "type": "object",
        "properties": {
          "lineNumber": {
            "type": "integer",
            "description": "Line number, unique within the return.",
            "format": "int32"
          },
          "orderLineNumber": {
            "type": "integer",
            "description": "Line number on the originating sales order.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number being returned.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the item.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "Quantity returned. Serialised as a decimal string.",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Unit price credited. Serialised as a decimal string.",
            "format": "double"
          },
          "lineTotal": {
            "type": "number",
            "description": "Line total excluding VAT. Serialised as a decimal string.",
            "format": "double"
          },
          "condition": {
            "type": "string",
            "description": "Condition the goods came back in.",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text notes on the line. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A line on a customer return."
      },
      "PublicReturnResponse": {
        "type": "object",
        "properties": {
          "returnNumber": {
            "type": "string",
            "description": "Unique return number.",
            "nullable": true
          },
          "orderNumber": {
            "type": "string",
            "description": "Order number the goods were returned from.",
            "nullable": true
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number the return belongs to. Null if the customer has no number.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicSalesReturnStatus"
          },
          "reason": {
            "type": "string",
            "description": "Why the goods came back: Defective, WrongItem, DamagedInTransit, CustomerRemorse, Warranty, QualityIssue, OverDelivery or Other.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Warehouse the goods are returned to.",
            "nullable": true
          },
          "returnDate": {
            "type": "string",
            "description": "Date the return was registered (ISO 8601 date).",
            "format": "date"
          },
          "receivedDate": {
            "type": "string",
            "description": "Date the goods arrived back (ISO 8601 date). Null until received.",
            "format": "date",
            "nullable": true
          },
          "rmaNumber": {
            "type": "string",
            "description": "The customer's own RMA reference. Null if not set.",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code the return is valued in.",
            "nullable": true
          },
          "totalAmount": {
            "type": "number",
            "description": "Net total of the returned lines. Serialised as a decimal string.",
            "format": "double"
          },
          "totalVat": {
            "type": "number",
            "description": "Total VAT on the returned lines. Serialised as a decimal string.",
            "format": "double"
          },
          "externalNotes": {
            "type": "string",
            "description": "Notes visible to the customer. Null if not set.",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnLineResponse"
            },
            "description": "The return's lines.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the return was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp when the return was last modified. Null if never modified.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A customer return (RMA) against a sales order."
      },
      "PublicSalesChannelType": {
        "enum": [
          "B2C",
          "B2B",
          "Marketplace",
          "App",
          "Store"
        ],
        "type": "string",
        "description": "Sales channel kinds exposed via the Public API.\n\nMirrors `Domain.SalesOrders.SalesChannelType` name-for-name and value-for-value so the\nquery projections can cast directly — a cast is translatable to SQL where a switch over a helper\nmethod is not. `PublicChannelEnumParityTests` fails the build if the two ever drift apart,\nwhich is what stops a new domain value from silently serialising as a bare number."
      },
      "PublicSalesOrderStatus": {
        "enum": [
          "Placed",
          "Released",
          "Closed",
          "Cancelled"
        ],
        "type": "string",
        "description": "Sales order status values exposed via the Public API.\nDraft orders are never visible through the public API.\n            \nThis describes where the order stands commercially, not what the warehouse is doing.\nWarehouse progress belongs to shipments (see GET /preview/orders/{id}/shipments) —\nan order can be split across several of them. How much has actually left the building\nis reported separately as PublicApi.Preview.Orders.Queries.PublicDeliveryStatus."
      },
      "PublicSalesReturnStatus": {
        "enum": [
          "Draft",
          "Approved",
          "Received",
          "CreditNoted",
          "Closed",
          "Cancelled"
        ],
        "type": "string",
        "description": "Status of a customer return."
      },
      "PublicSectionAlignment": {
        "enum": [
          "Left",
          "Center"
        ],
        "type": "string",
        "description": "Alignment of a section's heading. Mirrors `Domain.Ecom.SectionAlignment`."
      },
      "PublicSectionButton": {
        "required": [
          "label"
        ],
        "type": "object",
        "properties": {
          "label": {
            "maxLength": 100,
            "minLength": 1,
            "type": "string",
            "description": "The button's label."
          },
          "url": {
            "maxLength": 500,
            "type": "string",
            "description": "Where the button leads: a storefront path, an anchor, mailto:/tel: or an absolute http(s)\nURL. When PublicApi.Preview.ContentPages.Queries.PublicSectionButton.PageSlug is set, this is the page's current address on the way out\nand ignored on the way in.",
            "nullable": true
          },
          "pageSlug": {
            "maxLength": 100,
            "type": "string",
            "description": "The content page the button leads to, by slug in the same channel. The link then follows\nthe page when its address changes.",
            "nullable": true
          },
          "variant": {
            "$ref": "#/components/schemas/PublicSectionButtonVariant"
          },
          "openInNewTab": {
            "type": "boolean",
            "description": "Open in a new tab."
          }
        },
        "additionalProperties": false,
        "description": "A button under a section's heading."
      },
      "PublicSectionButtonVariant": {
        "enum": [
          "Primary",
          "Secondary",
          "Link"
        ],
        "type": "string",
        "description": "How a section button is drawn. Mirrors `Domain.Ecom.SectionButtonVariant`."
      },
      "PublicSectionContact": {
        "type": "object",
        "properties": {
          "showAddress": {
            "type": "boolean",
            "description": "Show the visiting address."
          },
          "showPhone": {
            "type": "boolean",
            "description": "Show the phone number."
          },
          "showEmail": {
            "type": "boolean",
            "description": "Show the email address."
          },
          "showOpeningHours": {
            "type": "boolean",
            "description": "Show the opening hours."
          },
          "mapImageUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "A map image (an image, not an embedded map).",
            "nullable": true
          },
          "directionsUrl": {
            "maxLength": 500,
            "type": "string",
            "description": "The link behind \"Get directions\".",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "What a Contact section shows."
      },
      "PublicSectionCustom": {
        "required": [
          "blockKey"
        ],
        "type": "object",
        "properties": {
          "blockKey": {
            "maxLength": 40,
            "minLength": 1,
            "type": "string",
            "description": "The block's key, unique in the channel, e.g. `prislista`."
          },
          "values": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonNode"
            },
            "description": "The values, keyed by field key. A list is an array of objects, an image\n`{ \"url\", \"alt\" }`, a link `{ \"url\", \"openInNewTab\" }`, a choice the option's key,\na date ISO 8601.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A custom block on a page: which block, and the values for its fields."
      },
      "PublicSectionEmbed": {
        "required": [
          "url"
        ],
        "type": "object",
        "properties": {
          "url": {
            "maxLength": 2048,
            "minLength": 1,
            "type": "string",
            "description": "The page to embed. An absolute https address."
          },
          "title": {
            "maxLength": 200,
            "type": "string",
            "description": "The frame's accessible name, read out by screen readers.",
            "nullable": true
          },
          "height": {
            "maximum": 4000,
            "minimum": 100,
            "type": "integer",
            "description": "The frame's height in pixels. Its width follows the section.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "An Embed section: an external https page shown in a sandboxed frame — a booking, a\nconfigurator, a form or a widget. The storefront allows the url's origin in the page's\nframe-src by itself."
      },
      "PublicSectionFaq": {
        "type": "object",
        "properties": {
          "source": {
            "$ref": "#/components/schemas/PublicFaqSource"
          },
          "articleCategory": {
            "maxLength": 100,
            "type": "string",
            "description": "The knowledge articles' category when `Source` is `KnowledgeArticles`. Empty\nmeans every category.",
            "nullable": true
          },
          "items": {
            "maxItems": 30,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSectionFaqItem"
            },
            "description": "The questions, in display order. Only used when `Source` is `Manual`.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A Faq section's questions."
      },
      "PublicSectionFaqItem": {
        "required": [
          "question"
        ],
        "type": "object",
        "properties": {
          "question": {
            "maxLength": 300,
            "minLength": 1,
            "type": "string",
            "description": "The question."
          },
          "answerHtml": {
            "maxLength": 5000,
            "type": "string",
            "description": "The answer, as HTML.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One question in a Faq section."
      },
      "PublicSectionForm": {
        "required": [
          "formToken"
        ],
        "type": "object",
        "properties": {
          "formToken": {
            "type": "string",
            "description": "The form, by its public token (the same token as in the form's embed link).",
            "format": "uuid"
          },
          "aside": {
            "$ref": "#/components/schemas/PublicFormAside"
          },
          "asideHtml": {
            "maxLength": 5000,
            "type": "string",
            "description": "The text next to the form when aside is Text.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A Form section's settings. What happens with a submission is set on the form in Fluit."
      },
      "PublicSectionLogo": {
        "required": [
          "imageUrl"
        ],
        "type": "object",
        "properties": {
          "imageUrl": {
            "maxLength": 2048,
            "minLength": 1,
            "type": "string",
            "description": "The logo image."
          },
          "altText": {
            "maxLength": 256,
            "type": "string",
            "description": "Alt text, normally the company name.",
            "nullable": true
          },
          "linkUrl": {
            "maxLength": 500,
            "type": "string",
            "description": "Where the logo links. Null makes it non-clickable.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One logo in a Logos section."
      },
      "PublicSectionLogos": {
        "type": "object",
        "properties": {
          "items": {
            "maxItems": 24,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSectionLogo"
            },
            "description": "The logos, in display order.",
            "nullable": true
          },
          "grayscale": {
            "type": "boolean",
            "description": "Show the logos in greyscale, in colour on hover."
          },
          "size": {
            "$ref": "#/components/schemas/PublicLogoSize"
          }
        },
        "additionalProperties": false,
        "description": "A Logos section's logos."
      },
      "PublicSectionMediaText": {
        "type": "object",
        "properties": {
          "mediaUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "The image.",
            "nullable": true
          },
          "altText": {
            "maxLength": 256,
            "type": "string",
            "description": "Alt text for the image.",
            "nullable": true
          },
          "videoUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "A video shown instead of the image; the image becomes its poster.",
            "nullable": true
          },
          "mediaPosition": {
            "$ref": "#/components/schemas/PublicMediaPosition"
          },
          "mediaAspect": {
            "$ref": "#/components/schemas/PublicMediaAspect"
          },
          "bodyHtml": {
            "maxLength": 50000,
            "type": "string",
            "description": "The text, as HTML.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A MediaText section's image and text."
      },
      "PublicSectionProductSpotlight": {
        "required": [
          "productNumber"
        ],
        "type": "object",
        "properties": {
          "productNumber": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "The product, by item number. Required on a ProductSpotlight section — omit it and the\nwrite is rejected with 400 naming sections[{index}].productSpotlight.productNumber."
          },
          "layout": {
            "$ref": "#/components/schemas/PublicSpotlightLayout"
          },
          "mediaPosition": {
            "$ref": "#/components/schemas/PublicMediaPosition"
          },
          "badge": {
            "maxLength": 60,
            "type": "string",
            "description": "Badge over the image, e.g. \"Firmware v1.2.0\".",
            "nullable": true
          },
          "bodyHtml": {
            "maxLength": 5000,
            "type": "string",
            "description": "The editor's pitch, as HTML. Empty falls back to the product's short description.",
            "nullable": true
          },
          "mediaUrl": {
            "maxLength": 2048,
            "type": "string",
            "description": "An image of your own instead of the product's.",
            "nullable": true
          },
          "altText": {
            "maxLength": 256,
            "type": "string",
            "description": "Alt text for that image. The product's own images carry theirs.",
            "nullable": true
          },
          "showKeySpecs": {
            "type": "boolean",
            "description": "Show the channel's filterable attributes for the product."
          },
          "showPrice": {
            "type": "boolean",
            "description": "Show the price. The storefront still decides what this visitor may see."
          },
          "showStock": {
            "type": "boolean",
            "description": "Show the stock status."
          },
          "showAddToCart": {
            "type": "boolean",
            "description": "Show the buy button. Needs the channel's webshop turned on."
          },
          "documents": {
            "$ref": "#/components/schemas/PublicSpotlightDocuments"
          },
          "documentIds": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The chosen documents when documents is Selected, at most ten. Opaque ids: read them from\na product and send them back unchanged. Ignored for every other value of documents.",
            "nullable": true
          },
          "documentCategory": {
            "maxLength": 50,
            "type": "string",
            "description": "The code of the document category listed when documents is Category, for example\n`Datasheet`. The tenant defines its own categories; the defaults are Datasheet,\nManual, Installation, CadDrawing, Brochure, Certificate, SafetySheet, Warranty, Firmware,\nSoftware and Other. New documents in that category then follow along on their own.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A ProductSpotlight section: one product shown large. Name, images, key specs, price, stock\nand documents are read from the product itself on every page view, so only the editor's own\nchoices live here."
      },
      "PublicSectionSpacing": {
        "enum": [
          "Normal",
          "Compact",
          "Spacious"
        ],
        "type": "string",
        "description": "Space above and below a section. Mirrors `Domain.Ecom.SectionSpacing`."
      },
      "PublicSectionTimeline": {
        "type": "object",
        "properties": {
          "steps": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSectionTimelineStep"
            },
            "description": "The steps, in display order.",
            "nullable": true
          },
          "marker": {
            "$ref": "#/components/schemas/PublicTimelineMarker"
          },
          "layout": {
            "$ref": "#/components/schemas/PublicTimelineLayout"
          }
        },
        "additionalProperties": false,
        "description": "A Timeline section's steps."
      },
      "PublicSectionTimelineOption": {
        "required": [
          "title"
        ],
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "The alternative's title, without a letter."
          },
          "bodyHtml": {
            "maxLength": 5000,
            "type": "string",
            "description": "The body text, as HTML.",
            "nullable": true
          },
          "buttons": {
            "maxItems": 3,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSectionButton"
            },
            "description": "Buttons in the alternative, at most three.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One of several paths through a step in a Timeline section."
      },
      "PublicSectionTimelineStep": {
        "required": [
          "title"
        ],
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "The step's title, without a number."
          },
          "bodyHtml": {
            "maxLength": 5000,
            "type": "string",
            "description": "The body text, as HTML.",
            "nullable": true
          },
          "iconName": {
            "maxLength": 64,
            "type": "string",
            "description": "Icon name, used when the marker is Icon.",
            "nullable": true
          },
          "buttons": {
            "maxItems": 3,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSectionButton"
            },
            "description": "Buttons in the step, at most three.",
            "nullable": true
          },
          "alternatives": {
            "maxItems": 4,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSectionTimelineOption"
            },
            "description": "Paths that lead through the same step, at most four.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One step in a Timeline section."
      },
      "PublicSectionTone": {
        "enum": [
          "Default",
          "Muted",
          "Ink",
          "Brand",
          "Accent"
        ],
        "type": "string",
        "description": "A section's background, from the channel's branding. Mirrors `Domain.Ecom.SectionTone`."
      },
      "PublicShipmentDetailResponse": {
        "type": "object",
        "properties": {
          "shipmentNumber": {
            "type": "string",
            "description": "Unique shipment number, e.g. `SHIP-2026-00128`.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicShipmentStatus"
          },
          "orderNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Order numbers this shipment fulfils. More than one on a consolidated shipment.",
            "nullable": true
          },
          "warehouseCode": {
            "type": "string",
            "description": "Code of the warehouse the shipment ships from.",
            "nullable": true
          },
          "shippingMethodName": {
            "type": "string",
            "description": "Name of the shipping method / carrier. Null if not set.",
            "nullable": true
          },
          "shippingMethodCode": {
            "type": "string",
            "description": "Code of the shipping method, as accepted by `shippingMethodCode` on PATCH. Null if no\nshipping method is set or the method has no code.",
            "nullable": true
          },
          "trackingNumber": {
            "type": "string",
            "description": "Carrier tracking number. Null until the shipment is booked with a carrier.",
            "nullable": true
          },
          "trackingUrl": {
            "type": "string",
            "description": "Link to the carrier's tracking page: the shipping method's tracking-link template with\nPublicApi.Preview.Shipments.Queries.PublicShipmentDetailResponse.TrackingNumber filled in. Null when either is missing. Safe to show to the end\ncustomer — it never carries Fluit's or the tenant's integration credentials.",
            "nullable": true
          },
          "externalBookingId": {
            "type": "string",
            "description": "Carrier's own booking reference. Null until booked.",
            "nullable": true
          },
          "plannedShipDate": {
            "type": "string",
            "description": "Planned ship date (ISO 8601 date). Null if not yet planned.",
            "format": "date",
            "nullable": true
          },
          "requestedDeliveryDate": {
            "type": "string",
            "description": "Requested delivery date (ISO 8601 date). Null if not set.",
            "format": "date",
            "nullable": true
          },
          "shippedDate": {
            "type": "string",
            "description": "UTC timestamp when the shipment was handed over to the carrier.",
            "format": "date-time",
            "nullable": true
          },
          "deliveredDate": {
            "type": "string",
            "description": "UTC timestamp when the shipment was delivered.",
            "format": "date-time",
            "nullable": true
          },
          "totalWeightKg": {
            "type": "number",
            "description": "Total weight in kilograms. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "incotermsCode": {
            "type": "string",
            "description": "Incoterms code, e.g. `DAP`. Null if not set.",
            "nullable": true
          },
          "goodsLabel": {
            "type": "string",
            "description": "Goods marking printed on the delivery note. Null if not set.",
            "nullable": true
          },
          "deliveryAddress": {
            "$ref": "#/components/schemas/PublicDeliveryAddressResponse"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicShipmentLineResponse"
            },
            "description": "All lines on the shipment, across every order it fulfils.",
            "nullable": true
          },
          "packages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicShipmentPackageResponse"
            },
            "description": "Packages registered on the shipment.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the shipment was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp when the shipment was last modified. Null if never modified.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A shipment with its delivery address, packages and the orders it fulfils."
      },
      "PublicShipmentLineResponse": {
        "type": "object",
        "properties": {
          "orderLineNumber": {
            "type": "integer",
            "description": "Line number of the sales order line this shipment line fulfils.",
            "format": "int32"
          },
          "orderNumber": {
            "type": "string",
            "description": "Order number of the sales order this line belongs to. Set on consolidated shipments.",
            "nullable": true
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number of the shipped item.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the shipped item.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "Quantity on this shipment. Serialised as a decimal string.",
            "format": "double"
          },
          "pickedQuantity": {
            "type": "number",
            "description": "Quantity picked so far. Serialised as a decimal string.",
            "format": "double"
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure code, e.g. `st`. Null when the line uses the item's base unit.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single shipment line, referencing the order line it fulfils."
      },
      "PublicShipmentPackageResponse": {
        "type": "object",
        "properties": {
          "packageNumber": {
            "type": "string",
            "description": "Package number, unique within the shipment.",
            "nullable": true
          },
          "trackingNumber": {
            "type": "string",
            "description": "Carrier tracking number for this individual package. Null until booked.",
            "nullable": true
          },
          "weightKg": {
            "type": "number",
            "description": "Weight in kilograms. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "lengthCm": {
            "type": "number",
            "description": "Length in centimetres. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "widthCm": {
            "type": "number",
            "description": "Width in centimetres. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "heightCm": {
            "type": "number",
            "description": "Height in centimetres. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text notes on the package. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A physical package (parcel) on a shipment."
      },
      "PublicShipmentResponse": {
        "type": "object",
        "properties": {
          "shipmentNumber": {
            "type": "string",
            "description": "Unique shipment number, e.g. `SHIP-2026-00128`.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicShipmentStatus"
          },
          "trackingNumber": {
            "type": "string",
            "description": "Carrier tracking number. Null until the shipment is booked with a carrier.",
            "nullable": true
          },
          "shippingMethodName": {
            "type": "string",
            "description": "Name of the shipping method / carrier. Null if not set.",
            "nullable": true
          },
          "shippingMethodCode": {
            "type": "string",
            "description": "Code of the shipping method, as accepted by `shippingMethodCode` on PATCH. Null if no\nshipping method is set or the method has no code.",
            "nullable": true
          },
          "trackingUrl": {
            "type": "string",
            "description": "Link to the carrier's tracking page: the shipping method's tracking-link template with\nPublicApi.Preview.Shipments.Queries.PublicShipmentResponse.TrackingNumber filled in. Null when either is missing. Safe to show to the end\ncustomer — it never carries Fluit's or the tenant's integration credentials.",
            "nullable": true
          },
          "plannedShipDate": {
            "type": "string",
            "description": "Planned ship date (ISO 8601 date). Null if not yet planned.",
            "format": "date",
            "nullable": true
          },
          "shippedDate": {
            "type": "string",
            "description": "UTC timestamp when the shipment was handed over to the carrier. Null if not yet shipped.",
            "format": "date-time",
            "nullable": true
          },
          "deliveredDate": {
            "type": "string",
            "description": "UTC timestamp when the shipment was delivered. Null if not yet delivered.",
            "format": "date-time",
            "nullable": true
          },
          "totalWeightKg": {
            "type": "number",
            "description": "Total weight in kilograms. Serialised as a decimal string. Null if not weighed.",
            "format": "double",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicShipmentLineResponse"
            },
            "description": "Shipment lines. Scoped to the addressed order when read through an order.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the shipment was created.",
            "format": "date-time"
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A shipment fulfilling (part of) a sales order."
      },
      "PublicShipmentStatus": {
        "enum": [
          "Hold",
          "Released",
          "Picking",
          "Picked",
          "ReadyForPickup",
          "Packing",
          "Packed",
          "Booked",
          "PickedUp",
          "InTransit",
          "Delivered",
          "Failed",
          "Cancelled"
        ],
        "type": "string",
        "description": "Shipment status values exposed via the Public API.\nMirrors the internal shipment lifecycle from warehouse release to delivery."
      },
      "PublicShippingMethodResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code used as `shippingMethodCode` in order creation.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the shipping method.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Shipping method / carrier available on sales orders."
      },
      "PublicSpotlightDocuments": {
        "enum": [
          "None",
          "Selected",
          "Category"
        ],
        "type": "string",
        "description": "Which of the product's documents a ProductSpotlight section lists.\nMirrors `Domain.Ecom.SpotlightDocuments`."
      },
      "PublicSpotlightLayout": {
        "enum": [
          "SideBySide",
          "Banner",
          "Row"
        ],
        "type": "string",
        "description": "How a ProductSpotlight section is drawn. Mirrors `Domain.Ecom.SpotlightLayout`."
      },
      "PublicStockDisplayMode": {
        "enum": [
          "ExactQuantity",
          "InStockOutOfStock",
          "LeadTime",
          "Hidden"
        ],
        "type": "string",
        "description": "How stock is presented for a published item.\nMirrors `Domain.Ecom.StockDisplayMode` — see PublicApi.Preview.Channels.Queries.PublicSalesChannelType for why."
      },
      "PublicSupplierContactResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Contact person's full name.",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Job title. Null if not set.",
            "nullable": true
          },
          "department": {
            "type": "string",
            "description": "Department. Null if not set.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address. Null if not set.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Phone number. Null if not set.",
            "nullable": true
          },
          "mobile": {
            "type": "string",
            "description": "Mobile phone number. Null if not set.",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the supplier's default contact."
          },
          "languageCode": {
            "type": "string",
            "description": "ISO 639-1 language code for communication with this contact. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A contact person at a supplier, returned by GET /preview/suppliers/{supplierNumber}/contacts."
      },
      "PublicSupplierItemResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number in Fluit — the business key used in item and order endpoints.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the item in Fluit.",
            "nullable": true
          },
          "supplierItemNumber": {
            "type": "string",
            "description": "The supplier's own article number for this item. Null if not set.",
            "nullable": true
          },
          "supplierDescription": {
            "type": "string",
            "description": "The supplier's own description of the item. Null if not set.",
            "nullable": true
          },
          "unitPrice": {
            "type": "number",
            "description": "Purchase price per unit, in the supplier's currency. Serialised as a decimal string.",
            "format": "double"
          },
          "minOrderQuantity": {
            "type": "number",
            "description": "Minimum order quantity. Null if the supplier has no minimum. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "orderMultiple": {
            "type": "number",
            "description": "Order quantities must be a multiple of this value. Null if unrestricted. Serialised as a decimal string.",
            "format": "double",
            "nullable": true
          },
          "supplierUnit": {
            "type": "string",
            "description": "The supplier's unit of measure, if it differs from ours. Null if the same.",
            "nullable": true
          },
          "conversionFactor": {
            "type": "number",
            "description": "Factor converting the supplier's unit to ours. Serialised as a decimal string.",
            "format": "double"
          },
          "leadTimeDays": {
            "type": "integer",
            "description": "Lead time in calendar days for this specific item. When null, MRP falls back to the\nitem-warehouse leadTimeDays, while the expected delivery date on a purchase order falls back\nto the supplier's default leadTimeDays.",
            "format": "int32",
            "nullable": true
          },
          "validFrom": {
            "type": "string",
            "description": "First date this price is valid. Null if valid from the beginning.",
            "format": "date",
            "nullable": true
          },
          "validTo": {
            "type": "string",
            "description": "Last date this price is valid. Null if it does not expire.",
            "format": "date",
            "nullable": true
          },
          "isPrimary": {
            "type": "boolean",
            "description": "Whether this supplier is the primary source for the item."
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the price row is active."
          }
        },
        "additionalProperties": false,
        "description": "A supplier-specific price and purchasing terms for one item, returned by\nGET /preview/suppliers/{supplierNumber}/items."
      },
      "PublicSupplierResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "supplierNumber": {
            "type": "string",
            "description": "Unique supplier number — business key used in all URL references.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Full company name.",
            "nullable": true
          },
          "organizationNumber": {
            "type": "string",
            "description": "Company registration number / org.nr. Null if not set.",
            "nullable": true
          },
          "vatNumber": {
            "type": "string",
            "description": "EU VAT registration number, e.g. `SE556012345601`. Null if not set.",
            "nullable": true
          },
          "isVatNumberValidated": {
            "type": "boolean",
            "description": "True when the VAT number has been confirmed against the EU VIES register."
          },
          "contactPerson": {
            "type": "string",
            "description": "Primary contact person at the supplier. Null if not set.",
            "nullable": true
          },
          "purchaseOrderEmail": {
            "type": "string",
            "description": "Email address purchase orders are sent to. Null if not set.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Primary phone number. Null if not set.",
            "nullable": true
          },
          "street1": {
            "type": "string",
            "description": "Street address line 1. Null if not set.",
            "nullable": true
          },
          "street2": {
            "type": "string",
            "description": "Street address line 2 (suite, c/o, etc.). Null if not set.",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "description": "Postal / ZIP code. Null if not set.",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "City name. Null if not set.",
            "nullable": true
          },
          "countryCode": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`, `DE`. Null if not set.",
            "nullable": true
          },
          "currencyCode": {
            "type": "string",
            "description": "ISO 4217 currency code purchase orders to this supplier are placed in.",
            "nullable": true
          },
          "paymentTermCode": {
            "type": "string",
            "description": "Code of the supplier's default payment term — usable as `paymentTermCode`. Null if not set.",
            "nullable": true
          },
          "paymentTermName": {
            "type": "string",
            "description": "Display name of the payment term. Null if not set.",
            "nullable": true
          },
          "deliveryTermCode": {
            "type": "string",
            "description": "Code of the supplier's default delivery term / Incoterm. Null if not set.",
            "nullable": true
          },
          "deliveryTermName": {
            "type": "string",
            "description": "Display name of the delivery term. Null if not set.",
            "nullable": true
          },
          "leadTimeDays": {
            "type": "integer",
            "description": "Default lead time in calendar days from order to delivery. Null if not set.",
            "format": "int32",
            "nullable": true
          },
          "ourCustomerNumber": {
            "type": "string",
            "description": "Our customer number at the supplier — quoted on purchase orders. Null if not set.",
            "nullable": true
          },
          "website": {
            "type": "string",
            "description": "Supplier website URL. Null if not set.",
            "nullable": true
          },
          "languageCode": {
            "type": "string",
            "description": "ISO 639-1 language code used for purchase order documents, e.g. `sv`, `en`. Null if not set.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the supplier is active. Inactive suppliers cannot be used on new purchase orders."
          },
          "notes": {
            "type": "string",
            "description": "Free-text internal notes (not visible to the supplier). Null if not set.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the supplier record was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Supplier details returned by GET /preview/suppliers/{supplierNumber} and the list endpoint."
      },
      "PublicSupplyPolicy": {
        "enum": [
          "ToStock",
          "ToOrder"
        ],
        "type": "string",
        "description": "Whether an item is supplied to stock or to order. Mirrors `Domain.Items.SupplyPolicy`."
      },
      "PublicTaxClassResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable tax class code, e.g. `STANDARD`. This is the value on an item's `taxClassCode`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name, e.g. `Standard 25%`.",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the tenant default for new items."
          },
          "countryCode": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country the rate below applies to.",
            "nullable": true
          },
          "rate": {
            "type": "number",
            "description": "VAT rate in percent, e.g. `25.00`. Serialised as a decimal string.\nNull if no rate is configured for this class in the requested country.",
            "format": "double",
            "nullable": true
          },
          "taxCode": {
            "type": "string",
            "description": "Accounting tax code for the rate, e.g. `MP1`. Null if no rate applies.",
            "nullable": true
          },
          "validFrom": {
            "type": "string",
            "description": "Date the rate took effect (inclusive). Null if no rate applies.",
            "format": "date",
            "nullable": true
          },
          "validTo": {
            "type": "string",
            "description": "Date the rate stops applying (exclusive). Null if open-ended or if no rate applies.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A VAT class, with the rate that applies today in the requested country.\n\nThe rate is a function of (tax class, country, date) rather than a property of the class, so\nit is resolved per request. An item carries only `taxClassCode`; join it against this list."
      },
      "PublicTenantInfoResponse": {
        "type": "object",
        "properties": {
          "companyName": {
            "type": "string",
            "description": "Registered company name.",
            "nullable": true
          },
          "organizationNumber": {
            "type": "string",
            "description": "Organisation / company registration number, or `null` if not configured.",
            "nullable": true
          },
          "vatNumber": {
            "type": "string",
            "description": "VAT registration number, or `null` if not configured.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Company contact e-mail, or `null` if not configured.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Company phone number, or `null` if not configured.",
            "nullable": true
          },
          "website": {
            "type": "string",
            "description": "Company website URL, or `null` if not configured.",
            "nullable": true
          },
          "street1": {
            "type": "string",
            "description": "Street address line 1, or `null` if not configured.",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "description": "Postal / ZIP code, or `null` if not configured.",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "City, or `null` if not configured.",
            "nullable": true
          },
          "countryCode": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. `SE`. Null if not configured.",
            "nullable": true
          },
          "baseCurrencyCode": {
            "type": "string",
            "description": "ISO 4217 base currency code, e.g. `SEK`.",
            "nullable": true
          },
          "defaultLanguageCode": {
            "type": "string",
            "description": "ISO 639-1 default language code, e.g. `sv`.",
            "nullable": true
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone identifier, e.g. `Europe/Stockholm`.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Company and configuration details for the authenticated tenant."
      },
      "PublicTicketCommentResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier of the comment (UUID v7).",
            "format": "uuid"
          },
          "content": {
            "type": "string",
            "description": "The message body.",
            "nullable": true
          },
          "isInternal": {
            "type": "boolean",
            "description": "Whether the message is an internal note. Internal notes are only returned when the request\nasks for them explicitly, and must never be shown to the reporter."
          },
          "externalAuthorName": {
            "type": "string",
            "description": "Name of the author when the message came from outside the ERP — a reporter or an\nintegration. Null when an agent wrote it; agents are not identified in the public contract.",
            "nullable": true
          },
          "isFromAgent": {
            "type": "boolean",
            "description": "Whether the message was written by an agent inside the ERP rather than by the reporter."
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the message was written.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "A message on a ticket, as returned by GET /preview/tickets/{ticketNumber}/comments."
      },
      "PublicTicketPriority": {
        "enum": [
          "Low",
          "Normal",
          "High",
          "Critical"
        ],
        "type": "string",
        "description": "Ticket priority values exposed via the Public API.\nMirrors `Domain.Tickets.TicketPriority` — see PublicApi.Preview.Support.Queries.PublicTicketStatus."
      },
      "PublicTicketQueueResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique queue code used as `queueCode` on the ticket endpoints.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the queue.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "What the queue handles. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Ticket queue a ticket can be addressed to."
      },
      "PublicTicketResolutionType": {
        "enum": [
          "Fixed",
          "CannotReproduce",
          "Duplicate",
          "WontFix",
          "CustomerResolved",
          "RmaApproved",
          "RmaRejected",
          "Refunded",
          "Replaced",
          "ReturnVisitRequired",
          "ResolvedByInstruction",
          "FirmwareUpdate",
          "ConfigurationChange",
          "NoFaultFound"
        ],
        "type": "string",
        "description": "How a ticket was resolved, exposed via the Public API.\nMirrors `Domain.Tickets.TicketResolutionType` — see PublicApi.Preview.Support.Queries.PublicTicketStatus."
      },
      "PublicTicketResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal unique identifier (UUID v7).",
            "format": "uuid"
          },
          "ticketNumber": {
            "type": "string",
            "description": "Unique ticket number — business key used in all URL references, e.g. `TKT-2026-00042`.",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Short summary of the issue.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Full description as submitted. Null if not set.",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/PublicTicketType"
          },
          "status": {
            "$ref": "#/components/schemas/PublicTicketStatus"
          },
          "priority": {
            "$ref": "#/components/schemas/PublicTicketPriority"
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number of the customer the ticket belongs to. Null when the reporter could not be matched to a customer.",
            "nullable": true
          },
          "contactName": {
            "type": "string",
            "description": "Name of the person who reported the issue. Null if not set.",
            "nullable": true
          },
          "contactEmail": {
            "type": "string",
            "description": "Email address of the person who reported the issue. Null if not set.",
            "nullable": true
          },
          "contactPhone": {
            "type": "string",
            "description": "Phone number of the person who reported the issue. Null if not set.",
            "nullable": true
          },
          "queueCode": {
            "type": "string",
            "description": "Code of the ticket queue (team) the ticket is addressed to. Null when it is in no queue.",
            "nullable": true
          },
          "queueName": {
            "type": "string",
            "description": "Display name of the ticket queue. Null when the ticket is in no queue.",
            "nullable": true
          },
          "isAssigned": {
            "type": "boolean",
            "description": "Whether a named agent has picked the ticket up. Who that is stays internal."
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number of the product the ticket concerns. Null when no product is linked.",
            "nullable": true
          },
          "serialNumber": {
            "type": "string",
            "description": "Serial number as the reporter gave it. Free text — it does not have to exist in the serial register.",
            "nullable": true
          },
          "firmwareVersion": {
            "type": "string",
            "description": "Firmware version in the unit when the fault occurred. Null if not set.",
            "nullable": true
          },
          "hardwareRevision": {
            "type": "string",
            "description": "Hardware revision or batch of the unit. Null if not set.",
            "nullable": true
          },
          "isSuspectedBug": {
            "type": "boolean",
            "description": "Whether the ticket is flagged as a suspected product fault rather than handling."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tags on the ticket, sorted alphabetically. Empty when the ticket has none.",
            "nullable": true
          },
          "resolutionType": {
            "$ref": "#/components/schemas/PublicTicketResolutionType"
          },
          "resolutionNotes": {
            "type": "string",
            "description": "The resolution as described to the reporter. Null while unresolved or if not set.",
            "nullable": true
          },
          "firstResponseAt": {
            "type": "string",
            "description": "UTC timestamp of the first reply to the reporter. Null until answered.",
            "format": "date-time",
            "nullable": true
          },
          "slaResponseDue": {
            "type": "string",
            "description": "UTC deadline for the first reply under the ticket's SLA. Null when no SLA policy applies.",
            "format": "date-time",
            "nullable": true
          },
          "slaResolutionDue": {
            "type": "string",
            "description": "UTC deadline for resolution under the ticket's SLA. Null when no SLA policy applies.",
            "format": "date-time",
            "nullable": true
          },
          "slaResponseBreached": {
            "type": "boolean",
            "description": "Whether the response deadline was passed."
          },
          "slaResolutionBreached": {
            "type": "boolean",
            "description": "Whether the resolution deadline was passed."
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the ticket was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp of the last modification. Null if never modified after creation.",
            "format": "date-time",
            "nullable": true
          },
          "resolvedAt": {
            "type": "string",
            "description": "UTC timestamp when the ticket was resolved. Null while unresolved.",
            "format": "date-time",
            "nullable": true
          },
          "closedAt": {
            "type": "string",
            "description": "UTC timestamp when the ticket was closed. Null while open.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "Ticket details returned by the ticket endpoints."
      },
      "PublicTicketStatus": {
        "enum": [
          "New",
          "Triaged",
          "Assigned",
          "InProgress",
          "WaitingCustomer",
          "WaitingInternal",
          "OnHold",
          "Resolved",
          "Closed",
          "Cancelled"
        ],
        "type": "string",
        "description": "Ticket status values exposed via the Public API.\n\nMirrors `Domain.Tickets.TicketStatus` name-for-name and value-for-value so the projection\ncan cast the domain value straight across. `PublicTicketEnumParityTests` fails the build\nif the two drift apart, which is what stops a new domain value from silently serialising as a\nbare number."
      },
      "PublicTicketSubmissionType": {
        "enum": [
          "ServiceRequest",
          "Complaint",
          "Support",
          "Question"
        ],
        "type": "string",
        "description": "The ticket types an external caller may submit. A deliberately narrow subset of\nPublicApi.Preview.Support.Queries.PublicTicketType: RMA, warranty and internal tickets drive internal\nflows with their own required fields and are not created from a contact form."
      },
      "PublicTicketType": {
        "enum": [
          "ServiceIncident",
          "ServiceRequest",
          "Maintenance",
          "Installation",
          "Inspection",
          "Rma",
          "Warranty",
          "Complaint",
          "Support",
          "Question",
          "Internal",
          "Firmware",
          "FeatureRequest"
        ],
        "type": "string",
        "description": "Ticket type values exposed via the Public API.\nMirrors `Domain.Tickets.TicketType` — see PublicApi.Preview.Support.Queries.PublicTicketStatus."
      },
      "PublicTimelineLayout": {
        "enum": [
          "Vertical",
          "Horizontal"
        ],
        "type": "string",
        "description": "How the steps of a Timeline section are arranged. Mirrors `Domain.Ecom.TimelineLayout`."
      },
      "PublicTimelineMarker": {
        "enum": [
          "Number",
          "Icon",
          "Dot"
        ],
        "type": "string",
        "description": "What is drawn at each step in a Timeline section."
      },
      "PublicTrackingType": {
        "enum": [
          "None",
          "Serial",
          "SerialOut",
          "Batch",
          "BatchOut"
        ],
        "type": "string",
        "description": "How an item is tracked in a warehouse. Mirrors `Domain.Items.TrackingType`.\n\nTracking is configured <b>per warehouse</b>, so this value is only meaningful in the context of\none warehouse — the same item can be serial-tracked in one warehouse and untracked in another."
      },
      "PublicTransferOrderLineResponse": {
        "type": "object",
        "properties": {
          "lineNumber": {
            "type": "integer",
            "description": "Line number, unique within the transfer order.",
            "format": "int32"
          },
          "itemNumber": {
            "type": "string",
            "description": "Item number being transferred.",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "description": "Display name of the item.",
            "nullable": true
          },
          "requestedQuantity": {
            "type": "number",
            "description": "Quantity requested. Serialised as a decimal string.",
            "format": "double"
          },
          "pickedQuantity": {
            "type": "number",
            "description": "Quantity picked at the source warehouse. Serialised as a decimal string.",
            "format": "double"
          },
          "shippedQuantity": {
            "type": "number",
            "description": "Quantity shipped. Serialised as a decimal string.",
            "format": "double"
          },
          "receivedQuantity": {
            "type": "number",
            "description": "Quantity received at the destination. Serialised as a decimal string.",
            "format": "double"
          },
          "fromLocationCode": {
            "type": "string",
            "description": "Source location code. Null when not pinned to a location.",
            "nullable": true
          },
          "toLocationCode": {
            "type": "string",
            "description": "Destination location code. Null when not pinned to a location.",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text notes on the line. Null if not set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A line on a stock transfer."
      },
      "PublicTransferOrderResponse": {
        "type": "object",
        "properties": {
          "orderNumber": {
            "type": "string",
            "description": "Unique transfer order number.",
            "nullable": true
          },
          "fromWarehouseCode": {
            "type": "string",
            "description": "Code of the warehouse the stock leaves.",
            "nullable": true
          },
          "toWarehouseCode": {
            "type": "string",
            "description": "Code of the warehouse the stock arrives at.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/PublicTransferOrderStatus"
          },
          "requestedDate": {
            "type": "string",
            "description": "Requested arrival date (ISO 8601 date). Null if not set.",
            "format": "date",
            "nullable": true
          },
          "shippedDate": {
            "type": "string",
            "description": "UTC timestamp when the transfer was shipped. Null until shipped.",
            "format": "date-time",
            "nullable": true
          },
          "receivedDate": {
            "type": "string",
            "description": "UTC timestamp when the transfer was received. Null until received.",
            "format": "date-time",
            "nullable": true
          },
          "shippingMethodName": {
            "type": "string",
            "description": "Name of the shipping method / carrier. Null if not set.",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Free-text notes. Null if not set.",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicTransferOrderLineResponse"
            },
            "description": "The transfer's lines.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the transfer was created.",
            "format": "date-time"
          },
          "modifiedDate": {
            "type": "string",
            "description": "UTC timestamp when the transfer was last modified. Null if never modified.",
            "format": "date-time",
            "nullable": true
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A stock transfer between two warehouses."
      },
      "PublicTransferOrderStatus": {
        "enum": [
          "Draft",
          "Placed",
          "Released",
          "Picking",
          "ReadyToShip",
          "InTransit",
          "PartiallyReceived",
          "Received",
          "Cancelled"
        ],
        "type": "string",
        "description": "Status of a stock transfer between warehouses."
      },
      "PublicUnitResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique unit code used as `unit` on order lines, e.g. `ST`, `KG`.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the unit.",
            "nullable": true
          },
          "symbol": {
            "type": "string",
            "description": "Short symbol for presentation, e.g. `kg`. Null if not set.",
            "nullable": true
          },
          "decimalPlaces": {
            "type": "integer",
            "description": "Number of decimals normally used for quantities in this unit.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Unit of measure usable on order lines."
      },
      "PublicWarehouseAvailability": {
        "type": "object",
        "properties": {
          "warehouseCode": {
            "type": "string",
            "description": "Warehouse code — usable as `warehouseCode` in order creation.",
            "nullable": true
          },
          "warehouseName": {
            "type": "string",
            "description": "Display name of the warehouse.",
            "nullable": true
          },
          "quantityOnHand": {
            "type": "number",
            "description": "Physical quantity on hand in this warehouse. Serialised as a decimal string.",
            "format": "double"
          },
          "allocatedQuantity": {
            "type": "number",
            "description": "Quantity reserved for orders in this warehouse. Serialised as a decimal string.",
            "format": "double"
          },
          "availableQuantity": {
            "type": "number",
            "description": "Quantity available for new orders (on hand − allocated). Serialised as a decimal string.",
            "format": "double"
          },
          "trackingType": {
            "$ref": "#/components/schemas/PublicTrackingType"
          },
          "requiresSerial": {
            "type": "boolean",
            "description": "Whether movements in this warehouse must carry serial numbers\n(`trackingType` is `Serial` or `SerialOut`). A receipt or shipment without\nthem is rejected."
          },
          "requiresBatch": {
            "type": "boolean",
            "description": "Whether movements in this warehouse must carry batch/lot numbers\n(`trackingType` is `Batch` or `BatchOut`)."
          },
          "replenishmentType": {
            "$ref": "#/components/schemas/PublicReplenishmentType"
          }
        },
        "additionalProperties": false,
        "description": "Stock availability for an item in a single warehouse."
      },
      "PublicWarehouseResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique warehouse code used as `warehouseCode` in order creation.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the warehouse.",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the tenant's default warehouse."
          }
        },
        "additionalProperties": false,
        "description": "Warehouse available for order fulfilment."
      },
      "PublicWorkOrderPriority": {
        "enum": [
          "Low",
          "Normal",
          "High",
          "Urgent"
        ],
        "type": "string",
        "description": "Work order priority values exposed via the Public API. Mirrors\n`Domain.WorkOrders.WorkOrderPriority`."
      },
      "PublicWorkOrderResponse": {
        "type": "object",
        "properties": {
          "workOrderNumber": {
            "type": "string",
            "description": "Unique work order number, e.g. `WO-2026-00042`.",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/PublicWorkOrderType"
          },
          "status": {
            "$ref": "#/components/schemas/PublicWorkOrderStatus"
          },
          "priority": {
            "$ref": "#/components/schemas/PublicWorkOrderPriority"
          },
          "title": {
            "type": "string",
            "description": "Short title describing the work.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Longer description of the work. Null if not set.",
            "nullable": true
          },
          "outputItemNumber": {
            "type": "string",
            "description": "Item number of the item being produced. Null for service and project orders.",
            "nullable": true
          },
          "plannedOutputQuantity": {
            "type": "number",
            "description": "Quantity planned to be produced. Serialised as a decimal string.",
            "format": "double"
          },
          "producedQuantity": {
            "type": "number",
            "description": "Quantity reported as produced so far. Serialised as a decimal string.",
            "format": "double"
          },
          "warehouseCode": {
            "type": "string",
            "description": "Code of the warehouse the output is received into. Null if not set.",
            "nullable": true
          },
          "customerNumber": {
            "type": "string",
            "description": "Customer number, when the work order belongs to a customer. Null otherwise.",
            "nullable": true
          },
          "salesOrderNumber": {
            "type": "string",
            "description": "Sales order number this work order fulfils. Null if not linked to an order.",
            "nullable": true
          },
          "plannedStart": {
            "type": "string",
            "description": "Planned start (UTC). Null if not planned.",
            "format": "date-time",
            "nullable": true
          },
          "plannedEnd": {
            "type": "string",
            "description": "Planned end (UTC). Null if not planned.",
            "format": "date-time",
            "nullable": true
          },
          "actualStart": {
            "type": "string",
            "description": "When work actually started (UTC). Null if not started.",
            "format": "date-time",
            "nullable": true
          },
          "actualEnd": {
            "type": "string",
            "description": "When work actually finished (UTC). Null if not finished.",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "UTC timestamp when the work order was created.",
            "format": "date-time"
          },
          "links": {
            "$ref": "#/components/schemas/PublicLinks"
          }
        },
        "additionalProperties": false,
        "description": "A work order as exposed by GET /preview/work-orders/{workOrderNumber}.\nReference data is addressed by business key, never by internal id."
      },
      "PublicWorkOrderStatus": {
        "enum": [
          "Draft",
          "Planned",
          "Waiting",
          "Active",
          "Paused",
          "Completed",
          "Closed",
          "Cancelled",
          "Estimate"
        ],
        "type": "string",
        "description": "Work order status values exposed via the Public API.\n\nMirrors `Domain.WorkOrders.WorkOrderStatus` name-for-name and value-for-value so the query\nprojections can cast directly — a cast is translatable to SQL where a switch over a helper\nmethod is not. `PublicWorkOrderEnumParityTests` fails the build if the two ever drift\napart, which is what stops a new domain value from silently serialising as a bare number."
      },
      "PublicWorkOrderType": {
        "enum": [
          "Manufacturing",
          "Project",
          "Service",
          "Maintenance"
        ],
        "type": "string",
        "description": "Work order type values exposed via the Public API. Mirrors `Domain.WorkOrders.WorkOrderType`."
      },
      "PutItemFeatureOptionRequest": {
        "required": [
          "code",
          "name"
        ],
        "type": "object",
        "properties": {
          "code": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "Option code, unique within the feature — what conditions reference."
          },
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Name shown in the configurator."
          },
          "itemNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "The item the option stands for — e.g. the seat or the fabric. It is pulled into the bill\nof materials when the option is chosen.",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Preselected option. At most one per feature."
          },
          "sortOrder": {
            "type": "integer",
            "description": "Position in the configurator. Defaults to the order of the list.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PutItemFeatureRequest": {
        "required": [
          "name",
          "options"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Name of the choice, e.g. \"Seat\"."
          },
          "isRequired": {
            "type": "boolean",
            "description": "Whether a choice must be made when the item is ordered."
          },
          "sortOrder": {
            "type": "integer",
            "description": "Position among the item's features. Defaults to last on creation.",
            "format": "int32",
            "nullable": true
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PutItemFeatureOptionRequest"
            },
            "description": "The complete list of options. Options left out are removed."
          },
          "priceFormula": {
            "maxLength": 1000,
            "type": "string",
            "description": "What the choice adds to the unit price. `SEAT_PRIS` adds the sales price of the item\nbehind the chosen option (the feature code followed by `_PRIS`); `SEAT_KOST` is its\ncost price. Numbers, other feature codes, + - * / ( ) and ROUND, CEILING, FLOOR, ABS, MIN, MAX\nare allowed. Omit when the choice does not change the price — like the rest of the request,\nleaving it out removes a formula set earlier.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PutItemFeatureResponse": {
        "type": "object",
        "properties": {
          "featureId": {
            "type": "string",
            "format": "uuid"
          },
          "created": {
            "type": "boolean",
            "description": "True when the feature did not exist before this call."
          },
          "changed": {
            "type": "boolean",
            "description": "True when the call changed anything. A re-run that sends the same request gets false."
          }
        },
        "additionalProperties": false
      },
      "ReceivePurchaseOrderLineRequest": {
        "type": "object",
        "properties": {
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Quantity received. Must be greater than zero.",
            "format": "double"
          },
          "locationCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Warehouse location to receive into. Defaults to the warehouse's default receiving location.",
            "nullable": true
          },
          "unitCost": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "Actual unit cost for this receipt. Must not be negative. Defaults to the line's unit price.",
            "format": "double",
            "nullable": true
          },
          "serialNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Serial number, for serial-tracked items. Use serialNumbers to receive several units at once.",
            "nullable": true
          },
          "batchNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Batch / lot number, for batch-tracked items.",
            "nullable": true
          },
          "notes": {
            "maxLength": 500,
            "type": "string",
            "description": "Free-text notes stored on the receipt.",
            "nullable": true
          },
          "serialNumbers": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Serial numbers, one per unit received, for receiving several serial-tracked units in a single call. The count must equal quantity, the numbers must be unique, at most 100 fit in one call, and serialNumber must be omitted when this is supplied.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReceivePurchaseOrderLineResponse": {
        "type": "object",
        "properties": {
          "receiptId": {
            "type": "string",
            "description": "Internal unique identifier of the created receipt (UUID v7).",
            "format": "uuid"
          },
          "line": {
            "$ref": "#/components/schemas/PublicPurchaseOrderLineResponse"
          }
        },
        "additionalProperties": false,
        "description": "Receipt confirmation returned after goods have been booked into stock."
      },
      "ReceiveReturnRequest": {
        "type": "object",
        "properties": {
          "receivedDate": {
            "type": "string",
            "description": "Date the goods arrived. Defaults to today.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReceiveTransferOrderLineRequest": {
        "type": "object",
        "properties": {
          "quantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "exclusiveMinimum": true,
            "type": "number",
            "description": "Quantity received. Must be greater than zero and at most the shipped quantity.",
            "format": "double"
          },
          "toLocationCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Location to receive into. Defaults to the line's destination location.",
            "nullable": true
          },
          "serialNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Serial number, for serial-tracked items.",
            "nullable": true
          },
          "batchNumber": {
            "maxLength": 100,
            "type": "string",
            "description": "Batch / lot number, for batch-tracked items.",
            "nullable": true
          },
          "serialNumbers": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Serial numbers, one per unit received, for receiving several serial-tracked units in a single call. The count must equal quantity, the numbers must be unique, at most 100 fit in one call, and serialNumber must be omitted when this is supplied.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReconfigureConfigurationRequest": {
        "type": "object",
        "properties": {
          "values": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicConfigurationValueInput"
            },
            "description": "The full set of chosen values, replacing the previous set — anything left out of the list is cleared.\nOmit the field entirely to keep the current choices, e.g. when only changing the quantity.\nSend an empty array to clear every choice.",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "New quantity. Omit to keep the current one.",
            "format": "double",
            "nullable": true
          },
          "customerNumber": {
            "maxLength": 50,
            "type": "string",
            "description": "Customer to attach. Use it to claim a configuration that was saved anonymously. Omit to keep the current customer.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReopenTicketRequest": {
        "type": "object",
        "properties": {
          "note": {
            "maxLength": 1000,
            "type": "string",
            "description": "Why the ticket is being reopened. Stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ResolveTicketRequest": {
        "required": [
          "resolutionType"
        ],
        "type": "object",
        "properties": {
          "resolutionType": {
            "$ref": "#/components/schemas/TicketResolutionType"
          },
          "resolutionNotes": {
            "maxLength": 4000,
            "type": "string",
            "description": "The resolution. Internal when `customerMessage` is given; otherwise it is also what the\nreporter is told, as before. Optional.",
            "nullable": true
          },
          "rootCause": {
            "maxLength": 2000,
            "type": "string",
            "description": "What actually caused the issue. Internal. Optional.",
            "nullable": true
          },
          "notifyCustomer": {
            "type": "boolean",
            "description": "Whether the reporter is emailed that the ticket is resolved. Defaults to true."
          },
          "customerMessage": {
            "maxLength": 4000,
            "type": "string",
            "description": "What the reporter is told, in the email and the customer portal. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReturnLineCondition": {
        "enum": [
          "Resellable",
          "Damaged",
          "Defective",
          "ForDisposal"
        ],
        "type": "string"
      },
      "ReturnReason": {
        "enum": [
          "Defective",
          "WrongItem",
          "DamagedInTransit",
          "CustomerRemorse",
          "Warranty",
          "QualityIssue",
          "OverDelivery",
          "Other"
        ],
        "type": "string"
      },
      "SendPurchaseOrderRequest": {
        "type": "object",
        "properties": {
          "sendEmail": {
            "type": "boolean",
            "description": "Set to `true` to email the purchase order PDF to the supplier. Defaults to `false`,\nwhich only moves the order to Sent — use it when the order has already been transmitted by\nEDI or another channel."
          },
          "toEmail": {
            "maxLength": 200,
            "type": "string",
            "description": "Recipient address. Defaults to the supplier's purchase order email. Only used when sendEmail is true.",
            "format": "email",
            "nullable": true
          },
          "subject": {
            "maxLength": 200,
            "type": "string",
            "description": "Custom email subject. Only used when sendEmail is true.",
            "nullable": true
          },
          "message": {
            "maxLength": 4000,
            "type": "string",
            "description": "Custom email body. Only used when sendEmail is true.",
            "nullable": true
          },
          "language": {
            "maxLength": 10,
            "type": "string",
            "description": "Language for the attached PDF and — when subject and message are left out — for the email\ntext. ISO 639-1, e.g. `sv` or `en`; anything else falls back to English, which is\nwhat the PDF renders as. Defaults to the order's own language, then the supplier contact's,\nthen the supplier's.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SendQuoteMode": {
        "enum": [
          "Email",
          "MarkAsSent"
        ],
        "type": "string"
      },
      "SendQuoteRequest": {
        "type": "object",
        "properties": {
          "mode": {
            "$ref": "#/components/schemas/SendQuoteMode"
          },
          "toEmail": {
            "maxLength": 255,
            "type": "string",
            "description": "Recipient address. Required with mode Email unless the contact has one.",
            "format": "email",
            "nullable": true
          },
          "subject": {
            "maxLength": 200,
            "type": "string",
            "description": "Email subject. Defaults to the tenant's quote template.",
            "nullable": true
          },
          "message": {
            "maxLength": 4000,
            "type": "string",
            "description": "Email body. Defaults to the tenant's quote template.",
            "nullable": true
          },
          "language": {
            "maxLength": 10,
            "type": "string",
            "description": "ISO 639-1 language for the document, e.g. `sv`. Defaults to the customer's language.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SetItemAttributeRequest": {
        "type": "object",
        "properties": {
          "value": {
            "maxLength": 4000,
            "type": "string",
            "description": "The value to set. Use this for single-value attributes.",
            "nullable": true
          },
          "values": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The complete list of values, for attributes where isMultiValue is true. Values not included are removed. Max 50 values.",
            "nullable": true
          },
          "isVisibleOnWeb": {
            "type": "boolean",
            "description": "Overrides whether the attribute is shown on the web. Omit to use the attribute's default.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SetItemTranslationRequest": {
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 10000,
            "type": "string",
            "description": "Translated name. Omit or send null to remove the translation.",
            "nullable": true
          },
          "description": {
            "maxLength": 10000,
            "type": "string",
            "description": "Translated description.",
            "nullable": true
          },
          "shortDescription": {
            "maxLength": 10000,
            "type": "string",
            "description": "Translated short description.",
            "nullable": true
          },
          "metaTitle": {
            "maxLength": 10000,
            "type": "string",
            "description": "Translated title for search engines.",
            "nullable": true
          },
          "metaDescription": {
            "maxLength": 10000,
            "type": "string",
            "description": "Translated description for search engines.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SetPriceListLineRequest": {
        "required": [
          "unitPrice"
        ],
        "type": "object",
        "properties": {
          "unitPrice": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "The fixed price, in the price list's currency. Serialised as a decimal string.",
            "format": "double"
          },
          "minQuantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "The price applies from this quantity. Omit for the price from the first unit. Part of the\nline's key.",
            "format": "double",
            "nullable": true
          },
          "maxQuantity": {
            "maximum": 79228162514264337593543950335,
            "minimum": 0,
            "type": "number",
            "description": "Upper quantity limit. Omit for none; an existing limit is removed.",
            "format": "double",
            "nullable": true
          },
          "validFrom": {
            "type": "string",
            "description": "First day the price applies. Omit for a price without start date. Part of the line's key, so\na price change from a later date becomes a line of its own and leaves today's price alone.",
            "format": "date",
            "nullable": true
          },
          "validTo": {
            "type": "string",
            "description": "Last day the price applies. Omit for none; an existing end date is removed.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SourceChannel": {
        "enum": [
          "Phone",
          "Email",
          "Chat",
          "WebForm",
          "SocialMedia",
          "Sms",
          "InPerson",
          "CustomerPortal"
        ],
        "type": "string"
      },
      "StartTicketRequest": {
        "type": "object",
        "properties": {
          "note": {
            "maxLength": 1000,
            "type": "string",
            "description": "Note stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "TicketPriority": {
        "enum": [
          "Low",
          "Normal",
          "High",
          "Critical"
        ],
        "type": "string"
      },
      "TicketResolutionType": {
        "enum": [
          "Fixed",
          "CannotReproduce",
          "Duplicate",
          "WontFix",
          "CustomerResolved",
          "RmaApproved",
          "RmaRejected",
          "Refunded",
          "Replaced",
          "ReturnVisitRequired",
          "ResolvedByInstruction",
          "FirmwareUpdate",
          "ConfigurationChange",
          "NoFaultFound"
        ],
        "type": "string"
      },
      "TicketSource": {
        "enum": [
          "Phone",
          "Email",
          "WebPortal",
          "AutomaticAlert",
          "ScheduledMaintenance",
          "Internal",
          "Ecommerce",
          "Api",
          "WebForm"
        ],
        "type": "string"
      },
      "TicketStatus": {
        "enum": [
          "New",
          "Triaged",
          "Assigned",
          "InProgress",
          "WaitingCustomer",
          "WaitingInternal",
          "OnHold",
          "Resolved",
          "Closed",
          "Cancelled"
        ],
        "type": "string"
      },
      "TicketType": {
        "enum": [
          "ServiceIncident",
          "ServiceRequest",
          "Maintenance",
          "Installation",
          "Inspection",
          "Rma",
          "Warranty",
          "Complaint",
          "Support",
          "Question",
          "Internal",
          "Firmware",
          "FeatureRequest"
        ],
        "type": "string"
      },
      "TriageTicketRequest": {
        "required": [
          "priority"
        ],
        "type": "object",
        "properties": {
          "priority": {
            "$ref": "#/components/schemas/TicketPriority"
          },
          "note": {
            "maxLength": 1000,
            "type": "string",
            "description": "Note stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "WaitForCustomerOnTicketRequest": {
        "type": "object",
        "properties": {
          "note": {
            "maxLength": 1000,
            "type": "string",
            "description": "What the reporter was asked. Stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "WaitInternalOnTicketRequest": {
        "type": "object",
        "properties": {
          "note": {
            "maxLength": 1000,
            "type": "string",
            "description": "What is being waited for. Stored in the ticket's history. Optional.",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "description": "API key issued per tenant. Prefix: `fluit_live_sk_...`. Use this for machine-to-machine integrations.",
        "name": "X-Api-Key",
        "in": "header"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization code flow with PKCE. Clients register themselves at `/oauth/register` (RFC 7591); no client secret is issued or accepted. Use this when the calls need to be traceable to a person — the token carries the user who approved the connection. Discovery: `/.well-known/oauth-protected-resource/preview`.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.fluit.cloud/oauth/authorize",
            "tokenUrl": "https://api.fluit.cloud/oauth/token",
            "refreshUrl": "https://api.fluit.cloud/oauth/token",
            "scopes": {
              "preview:read": "Read data across the public API.",
              "preview:write": "Read, create and update data across the public API."
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "ApiKey": [ ]
    },
    {
      "OAuth2": [
        "preview:read"
      ]
    }
  ],
  "tags": [
    {
      "name": "Customers",
      "description": "Customers with their contact persons and delivery addresses. Addressed by customerNumber."
    },
    {
      "name": "Items",
      "description": "Items/products including stock availability, price calculation, units, attributes and assets. Addressed by itemNumber."
    },
    {
      "name": "Categories",
      "description": "Item categories — the catalogue tree items are filed under. Addressed by code; parentCode nests a category under another, so a tree is loaded parents-first."
    },
    {
      "name": "Brands",
      "description": "Brands items carry. Addressed by code."
    },
    {
      "name": "Channels",
      "description": "Sales channels — webshops, B2B portals, marketplaces and apps — and which items are published on each, with the channel-specific texts, SEO and ordering. Channels are addressed by channelCode, publications by the pair (itemNumber, channelCode). Publishing is opt-in: an item is only part of a channel's assortment once a publication exists. A channel here carries commercial terms only — currency, warehouse, price list, order type. How the storefront looks (branding, menus, content pages) is not part of this contract."
    },
    {
      "name": "ContentPages",
      "description": "Editorial content in a channel: the home page, plus standing pages, blog posts and news. The last three are the same record told apart by pageType, built from the same sections and carrying the same SEO. Addressed by the pair (channelCode, slug). The home page is built from the same sections but lives on the channel: one per channel, no slug, no publish state, addressed by channel code alone. A page's body is its section list, which is replaced whole with PUT .../config; the metadata is patched separately. Products, categories and suppliers referenced inside a section are named by business key, not by internal id."
    },
    {
      "name": "Redirects",
      "description": "URL redirects in a channel's web shop: the old addresses that send visitors on to a new one, applied before the storefront matches a route. Covers the redirects created by hand or over this API and the 301s Fluit records itself when a product, category or page changes slug. Addressed by the pair (channelCode, id): the source path contains slashes and does not fit in a path segment."
    },
    {
      "name": "Media",
      "description": "A channel's media library: the uploaded images and the editorial metadata around them. Files are uploaded as multipart/form-data and addressed by their id — unlike the rest of this API, because a file has no other stable, unique name; two uploads may legitimately be called hero.jpg. The url in the response is what goes into a page section or an article's featuredImageUrl; the file itself is served by the CDN and needs no API key."
    },
    {
      "name": "SalesOrders",
      "description": "Sales orders with lines, fulfilment status and shipments. Addressed by orderNumber. Draft orders are not visible."
    },
    {
      "name": "Configurations",
      "description": "Made-to-order products: read an item's configuration schema, price and validate a set of choices, save it as a configuration and turn it into a sales order. Addressed by configurationNumber. The schema endpoint lives at /preview/items/{itemNumber}/configuration because it belongs to the item, but it is grouped here so the whole configurator flow reads in one place."
    },
    {
      "name": "Suppliers",
      "description": "Suppliers with their contact persons and supplier-specific prices, minimum order quantities and lead times. Addressed by supplierNumber."
    },
    {
      "name": "PurchaseOrders",
      "description": "Purchase orders with lines, confirmation status and goods receipts. Addressed by orderNumber. Unlike sales orders, draft purchase orders are visible — an order created through this API starts in Draft."
    },
    {
      "name": "Tickets",
      "description": "Support tickets through their whole handling flow: submit one from a contact form, follow its status, update it, exchange messages with the reporter, route it to a team's queue and take it through triage, work, resolution and closure. Addressed by ticketNumber. Tickets created here land in the same queue as tickets created inside the ERP and from the support mailbox. Assignment to a named agent is not exposed — agents are ERP users, and this API routes work by queue instead. Queue codes come from GET /preview/reference/ticket-queues."
    },
    {
      "name": "Shipments",
      "description": "Shipments: the physical fulfilment of sales orders, from warehouse release through picking, packing and carrier booking to delivery. Addressed by shipmentNumber. A shipment can cover several orders (consolidation) and an order can have several shipments (partial delivery), so shipments are their own resource rather than a sub-resource of the order."
    },
    {
      "name": "Invoices",
      "description": "Sales invoices with their lines and totals. Addressed by invoiceNumber."
    },
    {
      "name": "PriceLists",
      "description": "Price lists and their prices per item. Addressed by the price list's code. A line is identified by itemNumber, minQuantity and validFrom, so today's price and a price change from a later date live side by side. The API writes fixed prices only; lines calculated from cost, the item's sales price or another price list are read-only here. The price one customer pays is under GET /preview/items/{itemNumber}/price."
    },
    {
      "name": "Quotes",
      "description": "Sales quotes with lines and validity. Addressed by quoteNumber. A quote that is accepted or explicitly converted becomes a sales order."
    },
    {
      "name": "Returns",
      "description": "Customer returns (RMA): register a return against a sales order, approve it and receive the goods back into stock. Addressed by returnNumber."
    },
    {
      "name": "Inventory",
      "description": "Stock on hand, the stock ledger and the operations that move it: adjustments, relocations and physical counts. Availability per item lives under Items; this tag covers what has happened and how to change it."
    },
    {
      "name": "TransferOrders",
      "description": "Stock transfers between warehouses, from release through shipping to receipt. Addressed by orderNumber."
    },
    {
      "name": "Receipts",
      "description": "Goods receipts — what physically arrived, from purchase orders and inbound transfers. Addressed by receiptNumber. Receiving against a purchase order line is done under PurchaseOrders."
    },
    {
      "name": "WorkOrders",
      "description": "Production and service work orders. Read-only. Addressed by workOrderNumber."
    },
    {
      "name": "Sync",
      "description": "Endpoints that exist for incremental synchronisation. The list endpoints' ?modifiedSince= covers records that were created or changed; GET /preview/deletions covers the ones that were removed, which no list endpoint can report because the row is gone."
    },
    {
      "name": "Reference",
      "description": "Read-only reference data: the valid codes for warehouses, currencies, payment/delivery terms, order types and shipping methods used in other requests."
    }
  ],
  "x-logo": {
    "url": "https://fluit.se/fluit-logo.svg",
    "altText": "Fluit ERP",
    "href": "https://fluit.se"
  },
  "x-tagGroups": [
    {
      "name": "Master data",
      "tags": [
        "Customers",
        "Items",
        "Categories",
        "Brands",
        "Suppliers"
      ]
    },
    {
      "name": "Sales",
      "tags": [
        "Quotes",
        "SalesOrders",
        "PriceLists",
        "Configurations",
        "Invoices",
        "Returns"
      ]
    },
    {
      "name": "Commerce",
      "tags": [
        "Channels",
        "ContentPages",
        "Media",
        "Redirects"
      ]
    },
    {
      "name": "Fulfilment",
      "tags": [
        "Shipments"
      ]
    },
    {
      "name": "Purchasing",
      "tags": [
        "PurchaseOrders",
        "Receipts"
      ]
    },
    {
      "name": "Warehouse",
      "tags": [
        "Inventory",
        "TransferOrders"
      ]
    },
    {
      "name": "Production",
      "tags": [
        "WorkOrders"
      ]
    },
    {
      "name": "Support",
      "tags": [
        "Tickets"
      ]
    },
    {
      "name": "Sync",
      "tags": [
        "Sync"
      ]
    },
    {
      "name": "Reference data",
      "tags": [
        "Reference"
      ]
    }
  ]
}