# Solya POS Docs > Documentation for Solya POS — the Centrale back-office, the Caisse point-of-sale, and the REST API. ## Docs - [Ask the in-till assistant a question](https://docs-pos.solya.app/api-reference/assistant/ask-the-in-till-assistant-a-question.md): Sends a free-text prompt to the till's built-in help assistant and returns its reply as PROSE. It backs the caisse `/ia` screen, where a cashier asks how to use the POS. WHY `avoid`: this operation answers about the product, never about your data — it cannot read a sale, a stock level or a customer,… - [Get the POS permission manifest](https://docs-pos.solya.app/api-reference/auth/get-the-pos-permission-manifest.md): Returns the product's declared permission CATALOGUE: every `pos.*` key this backend can enforce, a one-line English description of each, and the optional role bundles that group them. It is the vocabulary, never an assignment — it says which permissions EXIST, not who holds any of them, which is why… - [Request a single-use manager elevation grant](https://docs-pos.solya.app/api-reference/auth/request-a-single-use-manager-elevation-grant.md): PRIVILEGE ESCALATION. Presents a manager's subject and PIN and, on success, mints a short-lived SINGLE-USE token carrying exactly ONE `pos.*` scope, to be spent as the `x-elevation-token` header on one later `POST /v1/checkout/finalize`. The cashier's session is never touched: no token is re-issued… - [Resolve the authenticated actor's effective POS scopes](https://docs-pos.solya.app/api-reference/auth/resolve-the-authenticated-actors-effective-pos-scopes.md): Returns the `pos.*` scopes the CALLING credential currently holds. This is the discovery entry point: call it FIRST, once, before planning any other work, and use the answer to decide what to attempt. - [Resolve the authenticated actor's effective POS scopes (MCP gateway alias)](https://docs-pos.solya.app/api-reference/auth/resolve-the-authenticated-actors-effective-pos-scopes-mcp-gateway-alias.md): Compatibility alias of `GET /v1/auth/whoami` mounted at `/api/auth/whoami` for the `solya-api-mcp` gateway, which hardcodes that path for its permission-aware discovery. It is IDENTICAL to the canonical operation in every respect — same authentication, same (empty) scope requirement, and the same `{… - [Set or rotate the calling actor's own elevation PIN](https://docs-pos.solya.app/api-reference/auth/set-or-rotate-the-calling-actors-own-elevation-pin.md): Enrols (or rotates) the elevation PIN of the AUTHENTICATED caller. The subject is taken from the bearer token and is not a field you can send, so there is no request that sets somebody else's PIN — that is the property the whole channel rests on: an elevation must prove who was physically present. - [Grant SMS credits to the account wallet](https://docs-pos.solya.app/api-reference/billing/grant-sms-credits-to-the-account-wallet.md): Adds `amount` SMS credits (a strictly positive integer) to the single account wallet and records them as an `adjustment` entry on the credit ledger, with the optional `source` kept as the operator note. This is the UNPAID path: no money changes hands and Stripe is not involved, so use it for pilots,… - [Open a Stripe Checkout session for a credit top-up](https://docs-pos.solya.app/api-reference/billing/open-a-stripe-checkout-session-for-a-credit-top-up.md): Opens a Stripe Checkout session to buy the one-off pack `packId` and returns the session `id` plus the hosted `url` a human must be redirected to. THIS MOVES MONEY once that page is paid, and the wallet is credited only later, by the `checkout.session.completed` webhook — so this response never refl… - [Open a Stripe Checkout session for a monthly plan](https://docs-pos.solya.app/api-reference/billing/open-a-stripe-checkout-session-for-a-monthly-plan.md): Opens a Stripe subscription Checkout session for the plan tier `tierId` and returns the session `id` plus the hosted `url` a human must be redirected to. THIS MUTATES A RECURRING SUBSCRIPTION once that page is paid: the tier is written onto the wallet and its monthly credits are granted by the `invo… - [Read the billing catalogue and current plan](https://docs-pos.solya.app/api-reference/billing/read-the-billing-catalogue-and-current-plan.md): Returns the purchasable one-off top-up `packs` and monthly `plans` (each with its credits, email fair-use cap and display price in cents), the `currentPlanTier` the wallet subscribes to (omitted when on no plan), and `enabled` — `false` when the deployment has no Stripe secret, meaning every checkou… - [Read the credit wallet, ledger and usage](https://docs-pos.solya.app/api-reference/billing/read-the-credit-wallet-ledger-and-usage.md): Returns everything the Centrale credits-and-notifications page renders in one call: the current `wallet` (materialized balance, subscribed plan tier and renewal date), every `ledger` movement (top-ups, plan grants, debits, refunds, adjustments), the `usage` events each send produced, the per-store `… - [Bulk-import products](https://docs-pos.solya.app/api-reference/catalog/bulk-import-products.md): Creates many products from a batch of drafts through the SAME create path, returning a per-row report (`created` / `skipped` when it already exists / `failed` with a reason). Idempotent: re-posting the same batch skips existing rows. Invalid rows are REPORTED, not rejected — the batch still returns… - [Clear a store price override](https://docs-pos.solya.app/api-reference/catalog/clear-a-store-price-override.md): Removes the store override for a (store, sku), returning the till to the base catalog price. Pass `?store=&sku=`. Idempotent — clearing an absent override reports `{ cleared: false }`, never an error. Requires the kernel `price:override` grant (403 without). - [Create a brand](https://docs-pos.solya.app/api-reference/catalog/create-a-brand.md): Creates one brand from a full directory draft. The `id` is caller-supplied (a slug derived from the code); `active` defaults to `true`. 409s when a brand with the same id already exists (a create never overwrites). 400s on a malformed body (e.g. an empty name). - [Create a kit](https://docs-pos.solya.app/api-reference/catalog/create-a-kit.md): Defines one kit / coffret under a SERVER-MINTED id (the response carries it), landing at version 1 and active. The bill of materials must be non-empty and its component SKUs DISTINCT (a duplicate line 400s). An optional `priceCents` overrides the components sum. This is authoring only — selling a ki… - [Create a product](https://docs-pos.solya.app/api-reference/catalog/create-a-product.md): Creates one catalog product from a full draft (merchandising fields + at least one SKU with its HT master price). Returns the persisted product at version 1. 409s when a product with the same id already exists. - [Create a taxonomy axis](https://docs-pos.solya.app/api-reference/catalog/create-a-taxonomy-axis.md): Creates one classification axis under a caller-supplied id, optionally with an initial node tree (`roots` defaults to empty). 409s when the id already exists; 400s on a bad `scope`/`source` enum or an empty name. - [Deactivate a product's markdown schedule](https://docs-pos.solya.app/api-reference/catalog/deactivate-a-products-markdown-schedule.md): Removes a product's markdown schedule, returning the till to the base price. Reports whether one existed (`{ deactivated: true|false }`); idempotent. - [Deactivate (archive) a brand](https://docs-pos.solya.app/api-reference/catalog/deactivate-archive-a-brand.md): Soft-archives a brand by flipping its `active` flag to `false` — never a physical delete (historic products still reference it), so the brand still reads back as inactive. Idempotent. 404s for an unknown brand. - [Deactivate (archive) a kit](https://docs-pos.solya.app/api-reference/catalog/deactivate-archive-a-kit.md): Soft-archives a kit (flips `active` to `false`) — it lists as inactive and stops resolving. Never a physical delete. 404s for an unknown kit. - [Deactivate (archive) a taxonomy axis](https://docs-pos.solya.app/api-reference/catalog/deactivate-archive-a-taxonomy-axis.md): Soft-archives an axis by flipping its `active` flag to `false` — never a physical delete, so the axis still reads back as inactive. 404s for an unknown axis. - [Get a brand by id](https://docs-pos.solya.app/api-reference/catalog/get-a-brand-by-id.md): Returns the full directory row for one brand (identity, `code`, `country`, `active`, optional `logoUrl`/`supplierId`). 404s when no brand carries the given id. - [Get a product by id](https://docs-pos.solya.app/api-reference/catalog/get-a-product-by-id.md): Returns the full catalog read model for one product. 404s when no product carries the given id. - [Get a product's priced sellable units](https://docs-pos.solya.app/api-reference/catalog/get-a-products-priced-sellable-units.md): Projects the priced (TTC + VAT per SKU) sellable units the till builds a cart line from. Pass `?store=` to re-price through that store's overrides; without it the base catalog price stands. 404s for a product with no master pricing record. - [Get a taxonomy axis by id](https://docs-pos.solya.app/api-reference/catalog/get-a-taxonomy-axis-by-id.md): Returns one classification axis (identity, `scope`, `source`, the node tree, and the `active` flag). 404s when no axis carries the given id. - [Global cross-entity search](https://docs-pos.solya.app/api-reference/catalog/global-cross-entity-search.md): Searches products, customers and brands in one call, matched case-insensitively on name / label / SKU references. Each source is scanned in full — the route pages every product / customer / brand directory to completion before matching — so a hit is never hidden behind a page cap, even on a book of… - [List a brand's suppliers](https://docs-pos.solya.app/api-reference/catalog/list-a-brands-suppliers.md): Returns the set of supplier ids that sell a brand (a brand can be sold by several vendors). The set starts empty. 404s for an unknown brand. - [List a store's price overrides](https://docs-pos.solya.app/api-reference/catalog/list-a-stores-price-overrides.md): Returns every store-scoped override authored for a store (the back-office authoring grid). Pass `?store=` — it is REQUIRED (a request without it 400s). Each override REPLACES the base catalog price for its (store, sku) while active. For the resulting sellable price a till uses, read `GET /produc… - [List catalog brands](https://docs-pos.solya.app/api-reference/catalog/list-catalog-brands.md): Returns one page of the merchandising brand directory (the 'Marques' list). Optionally narrow by `country` of origin and/or the `active` flag, and sort by `name` or `code`. Walk the result with `page`/`pageSize` (max 100); `total`/`pageCount` tell you when to stop. Use this to discover a brand's id… - [List catalog kits](https://docs-pos.solya.app/api-reference/catalog/list-catalog-kits.md): Returns every kit / coffret with its authoring metadata (`name`, `active`, `version`) and bill of materials. Includes deactivated kits (`active: false`). Use this to discover a kit id before a resolve/update. - [List catalog products](https://docs-pos.solya.app/api-reference/catalog/list-catalog-products.md): Returns one page of the catalog read model, optionally filtered by status and sorted. Use `page`/`pageSize` (max 100) to walk the result; `total`/`pageCount` let you know when to stop. This is the read model — for a sellable price use the units operation. - [List markdown schedules](https://docs-pos.solya.app/api-reference/catalog/list-markdown-schedules.md): Returns every authored markdown (planned clearance) schedule — the authoring directory. A markdown steps a product's price down over time; this lists the SCHEDULES, not the resolved price. For a product's effective price now, use the resolve operation. - [List taxonomy axes](https://docs-pos.solya.app/api-reference/catalog/list-taxonomy-axes.md): Returns every classification axis (e.g. Couleur, Taille, Famille) with its full unbounded-depth node tree. An axis's `scope` says what it classifies (`product` / `variant` / `movement`); the `variant` axes are the ones that build SKU-group labels. Use this to discover an axis id before a get/update. - [Replace a brand's supplier set](https://docs-pos.solya.app/api-reference/catalog/replace-a-brands-supplier-set.md): REPLACES the whole set of suppliers linked to a brand (add/remove is expressed as the new set, so a save is idempotent). The brand id rides the PATH, the supplier ids the body; a repeated id is deduplicated. An empty array clears every link. 404s for an unknown brand; 400s on a missing `supplierIds`… - [Resolve a kit's price and explosion](https://docs-pos.solya.app/api-reference/catalog/resolve-a-kits-price-and-explosion.md): Previews a kit's price (from its components via the server's price authority, or the override) and the explosion of selling `?quantity=` of it (default 1): the component stock movements = n × each component quantity. `missingSkuIds` lists components the server could not price (treated as 0 in the… - [Resolve a product's markdown price](https://docs-pos.solya.app/api-reference/catalog/resolve-a-products-markdown-price.md): Resolves a product's effective clearance price AT NOW: the latest step whose `fromDate` is on-or-before now wins (before the first step the master price stands). `source` names the layer that applied (`master`/`fixed`/`percent`). 404s for a product with no schedule. - [Set a product's markdown schedule](https://docs-pos.solya.app/api-reference/catalog/set-a-products-markdown-schedule.md): Upserts a product's markdown schedule (a master base price plus ordered steps). Steps must be STRICTLY ascending by `fromDate`. A first write lands at version 1; a later write goes through optimistic concurrency (`expectedVersion`). Requires the kernel `price:override` grant (403 without). 409s on a… - [Set a store price override](https://docs-pos.solya.app/api-reference/catalog/set-a-store-price-override.md): Upserts a store-scoped override for a (store, sku): a first write inserts at version 1, a later write goes through optimistic concurrency (`expectedVersion`). The override is keyed on the SELLABLE-UNIT id, carried as `productId`. An optional validity window (`validFrom`/`validTo`, ISO-8601, `validFr… - [Update a brand](https://docs-pos.solya.app/api-reference/catalog/update-a-brand.md): Replaces a brand's directory fields (name / code / country / active / logo) from a full draft. The PATH `brandId` is authoritative — an `id` in the body is ignored, so you cannot address one brand in the URL and mutate another. 404s for an unknown brand (never an implicit create). - [Update a kit](https://docs-pos.solya.app/api-reference/catalog/update-a-kit.md): Replaces a kit's name / components / optional price. The PATH `id` addresses the kit; the body carries the new definition plus the `expectedVersion` you last read. Component SKUs must stay DISTINCT. 404s for an unknown kit; 409s on a stale `expectedVersion`. - [Update a product](https://docs-pos.solya.app/api-reference/catalog/update-a-product.md): Replaces a product from a full draft plus the `expectedVersion` you last read; the path id is authoritative over any body id. Returns the product at the bumped version. 404s for an unknown product; 409s on a stale `expectedVersion`. - [Update a taxonomy axis](https://docs-pos.solya.app/api-reference/catalog/update-a-taxonomy-axis.md): Replaces a whole axis (name / scope / source / tree / active) by id — the persistence anchor the back-office tree editor saves every edit through. The PATH `axisId` is authoritative — an `id` in the body is ignored. The `active` flag is preserved when the body omits it (a plain tree save never resur… - [Accept a quote](https://docs-pos.solya.app/api-reference/checkout/accept-a-quote.md): Records the customer's acceptance of a `sent` quote, flipping it to `accepted` (only while still within its validity window). 404s for an unknown quote; 422s when the quote is not `sent` or its validity has lapsed. - [Book an appointment](https://docs-pos.solya.app/api-reference/checkout/book-an-appointment.md): Books a customer with a sales associate for a half-open `[startsAt, endsAt)` slot (ISO 8601 instants the server coerces), creating it `requested`. The slot must be forward-ordered and in the future. 409s when the slot overlaps another active booking for the same associate, or when the id already exi… - [Cancel a hold](https://docs-pos.solya.app/api-reference/checkout/cancel-a-hold.md): Releases a `held` reservation before it is fulfilled or lapses, flipping it to `cancelled` and returning it. Sends no body — the hold is addressed by the path id. 404s for an unknown hold; 422s when the hold is not `held`. - [Cancel a quote](https://docs-pos.solya.app/api-reference/checkout/cancel-a-quote.md): Withdraws a `draft` or `sent` quote, flipping it to `cancelled`. 404s for an unknown quote; 422s when the quote is already accepted/expired/cancelled. - [Cancel an appointment](https://docs-pos.solya.app/api-reference/checkout/cancel-an-appointment.md): Flips the appointment to `cancelled`. 404s for an unknown appointment; 422s when the current status does not permit the transition. - [Close a register session](https://docs-pos.solya.app/api-reference/checkout/close-a-register-session.md): Closes an `open` session against the physically `countedCents` cash and reconciles the drawer: expected = opening float + Σ movements, variance = counted − expected (negative is a shortage, positive an overage). The session is addressed by the PATH id (authoritative — a body `sessionId` is ignored).… - [Complete an appointment](https://docs-pos.solya.app/api-reference/checkout/complete-an-appointment.md): Flips the appointment to `completed`. 404s for an unknown appointment; 422s when the current status does not permit the transition. - [Confirm an appointment](https://docs-pos.solya.app/api-reference/checkout/confirm-an-appointment.md): Flips the appointment to `confirmed`. 404s for an unknown appointment; 422s when the current status does not permit the transition. - [Create a quote](https://docs-pos.solya.app/api-reference/checkout/create-a-quote.md): Draws up a priced quote in the `draft` state from at least one priced line. `validUntil` is an ISO 8601 instant (the server coerces it). 409s when a quote with the same id already exists; 422s when `validUntil` is already in the past. - [Drop a parked sale](https://docs-pos.solya.app/api-reference/checkout/drop-a-parked-sale.md): Discards an `open` parked sale without resuming it, flipping it to `dropped` and returning it. Sends no body — the sale is addressed by the path id. 404s for an unknown sale; 409s when the sale is no longer open (already resumed or dropped). - [Finalize a settled sale](https://docs-pos.solya.app/api-reference/checkout/finalize-a-settled-sale.md): Turns a settled cart plus its tenders into one idempotent sale event, booked against the register session (201). This is the ONLY way to commit a sale. The submitted `cart` prices are ADVISORY — the server re-prices every catalog line from its own reference authority (plus any `declaredDiscounts`, a… - [Fulfil a hold](https://docs-pos.solya.app/api-reference/checkout/fulfil-a-hold.md): Flips a `held` reservation to `fulfilled` when the customer completes the purchase, and returns it. Sends no body — the hold is addressed by the path id. 404s for an unknown hold; 422s when the hold is not `held` (already fulfilled, cancelled or expired). - [Get a deposit by id](https://docs-pos.solya.app/api-reference/checkout/get-a-deposit-by-id.md): Returns one deposit. 404s when no deposit carries the given id. - [Get a parked sale by id](https://docs-pos.solya.app/api-reference/checkout/get-a-parked-sale-by-id.md): Returns one parked sale with its exact cart snapshot (restored byte-identically on resume), whatever its lifecycle status. 404s when no parked sale carries the given id. - [Get a quote by id](https://docs-pos.solya.app/api-reference/checkout/get-a-quote-by-id.md): Returns one priced quote. 404s when no quote carries the given id. - [Get a register session by id](https://docs-pos.solya.app/api-reference/checkout/get-a-register-session-by-id.md): Returns the full register-session read model: its opening float, running cash movements, lifecycle status (`open` / `closed`) and — once closed — the reconciliation (`closing`). Use it to inspect a drawer or read back a Z close. 404s when no session carries the given id. - [Get a reservation by id](https://docs-pos.solya.app/api-reference/checkout/get-a-reservation-by-id.md): Returns one in-store hold: the SKU and quantity held, the customer and store, the `holdUntil` deadline, an optional deposit reference and the lifecycle status. 404s when no reservation carries the given id. - [Get an appointment by id](https://docs-pos.solya.app/api-reference/checkout/get-an-appointment-by-id.md): Returns one booking. 404s when no appointment carries the given id. - [List appointments](https://docs-pos.solya.app/api-reference/checkout/list-appointments.md): Returns the bookings as a flat array, optionally narrowed by `associate`, `customer`, `store`, `status` (requested | confirmed | completed | cancelled | no-show) and/or `timeframe` (`upcoming` | `past`, relative to the server clock). For a single booking use the get operation. - [List deposits](https://docs-pos.solya.app/api-reference/checkout/list-deposits.md): Returns one page of the special-order down-payments, optionally narrowed by `store` and/or `status` (open | settled). Use `page`/`pageSize` (max 100) to walk the result; `total`/`pageCount` tell you when to stop. - [List in-store holds](https://docs-pos.solya.app/api-reference/checkout/list-in-store-holds.md): Returns the in-store 'Reserve here' holds, optionally narrowed by `?store=` and/or `?status=held|fulfilled|cancelled|expired`. Use it to render the counter list. Returns an array (empty when none match). - [List open parked sales](https://docs-pos.solya.app/api-reference/checkout/list-open-parked-sales.md): Returns the `open` held carts (the 'Ventes en attente' list) — the only listable state; resumed and dropped sales are excluded. Pass `?store=` to narrow to one store so a sale parked there can be resumed from another till. Returns an array (empty when none). - [List quotes](https://docs-pos.solya.app/api-reference/checkout/list-quotes.md): Returns the quotes as a flat array, newest-first, optionally narrowed by `customer`, `store` and/or `status` (draft | sent | accepted | expired | cancelled). This is the clienteling devis list — for a single estimate use the get operation. - [Mark an appointment as a no-show](https://docs-pos.solya.app/api-reference/checkout/mark-an-appointment-as-a-no-show.md): Flips the appointment to `no-show`. 404s for an unknown appointment; 422s when the current status does not permit the transition. - [Open a deposit](https://docs-pos.solya.app/api-reference/checkout/open-a-deposit.md): Opens a deposit against a special order with an upfront down-payment, creating it `open`. Money is integer cents; the down-payment must not exceed the order total. 409s when a deposit with the same id already exists; 422s when the down-payment overpays the order total. - [Open a register session](https://docs-pos.solya.app/api-reference/checkout/open-a-register-session.md): Opens a register session with its opening cash float and the salesperson taking the shift. The session is always created `open` with no movements; the actor and the opened-at instant are stamped server-side from the context. Amounts are integer cents. 409s when a session with the same id already exi… - [Park a cart](https://docs-pos.solya.app/api-reference/checkout/park-a-cart.md): Sets the current cart aside under a stable id so it survives a reload and is resumable from another till in the same store. The sale is always created `open`; the actor and the parked-at instant are stamped server-side. The `cart` is stored verbatim. 409s when a parked sale with the same id already… - [Place an in-store hold](https://docs-pos.solya.app/api-reference/checkout/place-an-in-store-hold.md): Sets aside a quantity of a sellable unit for a customer until `holdUntil` (sent as an ISO 8601 string). The hold is an INTENT to reserve stock — the actual stock decrement lives in inventory/checkout, never here. Created in the `held` state; the actor and held-at instant are stamped server-side. 409… - [Record a cash movement on a session](https://docs-pos.solya.app/api-reference/checkout/record-a-cash-movement-on-a-session.md): Records one signed cash movement on an `open` drawer — a positive `amountCents` is a pay-in, a negative one a pay-out; zero is rejected. The session is addressed by the PATH id, which is authoritative: a `sessionId` in the body is ignored, never honoured. Returns the updated session. 404s for an unk… - [Resume a parked sale](https://docs-pos.solya.app/api-reference/checkout/resume-a-parked-sale.md): Flips an `open` parked sale to `resumed` and returns it, so the cashier can pick the basket back up. Sends no body — the sale is addressed by the path id. 404s for an unknown sale; 409s when the sale is no longer open (already resumed or dropped), which is how a resumed cart is prevented from being… - [Send a quote](https://docs-pos.solya.app/api-reference/checkout/send-a-quote.md): Issues a `draft` quote to the customer, flipping it to `sent`. 404s for an unknown quote; 422s when the quote is not in `draft`. - [Update a quote](https://docs-pos.solya.app/api-reference/checkout/update-a-quote.md): Replaces a draft quote's mutable fields (lines, customer, store, currency, validity). The PATH id is authoritative — any `id` in the body is ignored, so you cannot retarget the update at another quote. Only a `draft` quote is editable: 404s for an unknown quote, 422s once it has been sent/accepted. - [Record an age-verification attestation](https://docs-pos.solya.app/api-reference/compliance/record-an-age-verification-attestation.md): Appends ONE row to the durable age-verification compliance trail: that a check was performed, by which operator, for which transaction, when, and with what outcome. This is the record a merchant produces to a regulator, so only ever call it as the immediate consequence of a real check a human perfor… - [Erase a customer's personal data (GDPR)](https://docs-pos.solya.app/api-reference/customers/erase-a-customers-personal-data-gdpr.md): IRREVERSIBLY anonymizes one customer in place for a GDPR erasure request: the name becomes a placeholder, every contact field is cleared and marketing consent is withdrawn. The record and its id SURVIVE so past sales stay resolvable, and the loyalty ledger is untouched. Idempotent, and audited with… - [Export a customer's personal data (GDPR)](https://docs-pos.solya.app/api-reference/customers/export-a-customers-personal-data-gdpr.md): Assembles the full dossier held for one data subject — profile, marketing-consent standing and every settled ticket reference — for a GDPR portability request. It only READS, but it is a POST so it lands on `pos.customers.manage`: this is a privileged privacy act, not the ordinary customer read. The… - [Get a customer by id](https://docs-pos.solya.app/api-reference/customers/get-a-customer-by-id.md): Returns one customer's full record (identity, contact, loyalty tier/points, lifetime spend and the marketing `optIn` flag). Use it to confirm who you are about to act on before any write. 404s when no customer carries the id. - [Get a customer's consent record](https://docs-pos.solya.app/api-reference/customers/get-a-customers-consent-record.md): Returns the customer's granular consent standing: `entries` is the CURRENT decision per scope (`marketing_email`, `marketing_sms`, `loyalty_profiling`, `analytics`, `data_sharing`), `history` the full append-only audit trail. Check this before any marketing action — the coarse `optIn` flag on the cu… - [Get a customer's purchase history](https://docs-pos.solya.app/api-reference/customers/get-a-customers-purchase-history.md): Returns the customer's line-item purchase history — one row per priced ticket line, newest ticket first — projected from the sales read model. Reach for this to answer 'what has this customer bought'; use `listSales` instead for store-wide reporting. Pass `?store=` to restrict to one store. Amou… - [List customers](https://docs-pos.solya.app/api-reference/customers/list-customers.md): Returns one page of the customer directory. Reach for this to FIND a customer when you only know a tier or need to browse; when you already hold an id, call `getCustomer` instead. Filter with `tier` (the loyalty tier label, e.g. `Or`), order with `sortField` (`name`/`spend`/`points`) + `sortDirectio… - [Record a customer consent decision](https://docs-pos.solya.app/api-reference/customers/record-a-customer-consent-decision.md): Appends one consent decision to the customer's immutable trail. `status` picks the verb: `granted` records consent for the `scope`, `withdrawn` revokes it. `source` says where the decision was captured (`counter`, `kiosk`, `web`, `phone`) and is part of the legal record — state it truthfully. Only e… - [Register a customer](https://docs-pos.solya.app/api-reference/customers/register-a-customer.md): Registers a new customer from a name plus optional contact details and the GDPR marketing `optIn` flag. Do NOT send an id — it is minted server-side (`cust-`) and any `id` you send is discarded, so you can never collide with an existing record. The new customer starts on the floor loyalty tier… - [Report the customer base by RFM segment](https://docs-pos.solya.app/api-reference/customers/report-the-customer-base-by-rfm-segment.md): Computes an RFM (Recency / Frequency / Monetary) segmentation over the whole customer base and returns the per-bucket population plus the individual customer rows. Reach for this to answer 'who should I target' or 'how healthy is the base'; use `listCustomers` when you just need the directory. Bucke… - [Update a customer profile](https://docs-pos.solya.app/api-reference/customers/update-a-customer-profile.md): Patches an existing customer's identity, contact and marketing-consent fields. PATCH semantics despite the verb: only the keys you send change, and an explicit `null` on a contact field CLEARS it (omitting the key leaves it untouched). The path id is authoritative — a body `id` is discarded. This ne… - [Get the active card-terminal provider](https://docs-pos.solya.app/api-reference/devices/get-the-active-card-terminal-provider.md): Reports which payment-service provider the network resolves to right now and how ready it is. Read this BEFORE `runPaymentTerminalTest` — it is the safe way to answer 'is the card terminal set up' without commanding any hardware. `provider` is the operator's selection (the `psp.provider` network set… - [Run the card-terminal round-trip self-test](https://docs-pos.solya.app/api-reference/devices/run-the-card-terminal-round-trip-self-test.md): Commands the resolved payment provider through two probes, in this order: authorize -> capture, then authorize -> void. It exists so a human on the till's peripherals screen can prove the terminal is wired; an agent should reach for it ONLY on an explicit operator request to test the terminal, never… - [Close (lock) a fiscal period](https://docs-pos.solya.app/api-reference/finance/close-lock-a-fiscal-period.md): LOCKS a fiscal period, sealing its cash truth so it can no longer be re-opened or re-stated (201). Address the period by an opaque `periodKey` (e.g. `2026-07`, or `2026-07:store-paris` for a per-store close); pass `store` and the inclusive `from` / `to` day window (`YYYY-MM-DD`, `from <= to`) to rec… - [Export the FEC accounting file](https://docs-pos.solya.app/api-reference/finance/export-the-fec-accounting-file.md): Returns the French FEC (Fichier des Écritures Comptables) for a date period over the per-ticket sales read model. REQUIRES `from` and `to` as `YYYY-MM-DD` with `from <= to`; a missing, malformed or inverted period returns 400. `format` defaults to `json` (the structured payload documented here: bala… - [Get a deposit batch by id](https://docs-pos.solya.app/api-reference/finance/get-a-deposit-batch-by-id.md): Returns one deposit batch by its id. 404s when no batch carries the given id. - [Get a finance entry by id](https://docs-pos.solya.app/api-reference/finance/get-a-finance-entry-by-id.md): Returns the finance read model for one till cash session by its id. 404s when no entry carries the given id. - [Get one session's cash discrepancy](https://docs-pos.solya.app/api-reference/finance/get-one-sessions-cash-discrepancy.md): Runs the core cash-discrepancy computation for one register session (expected vs counted drawer cash, the signed gap and its `shortage` / `overage` / `balanced` / `uncounted` verdict). 404s for an unknown session. - [List deposit batches](https://docs-pos.solya.app/api-reference/finance/list-deposit-batches.md): Returns the bank-deposit reconciliation batches, optionally narrowed to a `shop` and/or a lifecycle `status` (`open` / `reconciled`). This is the back-office deposit domain — DISTINCT from the register-session cash truth at `GET /finance`. - [List finalized sale tickets](https://docs-pos.solya.app/api-reference/finance/list-finalized-sale-tickets.md): Returns the finalized sale tickets (the back-office read model projected by the checkout finalize hook), optionally narrowed by `?store=` and/or a `?day=` UTC calendar day (`YYYY-MM-DD`). A malformed `day` facet 400s. This router never writes. For the rolled-up KPIs use the summary operation. - [List finance entries](https://docs-pos.solya.app/api-reference/finance/list-finance-entries.md): Returns one page of the finance read model — the LIVE projection of the register-session cash truth (one row per till session: opening float, expected vs counted drawer cash, signed variance). Optionally narrow by `store` (canonical store id) and `status` (`open` / `closed`), sort by `store` or `dat… - [Open a deposit batch](https://docs-pos.solya.app/api-reference/finance/open-a-deposit-batch.md): Opens a new deposit batch from an id, its shop and at least one declared tender line (all lines start pending settlement). Returns the opened batch at 201. 409s when a batch with the same id already exists. - [Reconcile a deposit batch](https://docs-pos.solya.app/api-reference/finance/reconcile-a-deposit-batch.md): Matches declared vs settled per line and freezes the batch (→ `reconciled`), returning the reconciliation totals. Takes NO body — the path `batchId` is the only input. 404s for an unknown batch; 422 when any line is still unsettled or the batch is already reconciled. - [Report cash discrepancies for a period](https://docs-pos.solya.app/api-reference/finance/report-cash-discrepancies-for-a-period.md): Returns the per-session expected-vs-counted cash variance report over the LIVE register-session projection, plus an aggregated summary. Optionally narrow by `from` / `to` (`YYYY-MM-DD`, inclusive; `from <= to`) and `store`; absent bounds mean all time. A malformed or inverted period returns 400. - [Report the period close](https://docs-pos.solya.app/api-reference/finance/report-the-period-close.md): Returns the period-close aggregate — the overall cash-variance summary plus a per-store breakdown — over the same register-session projection. Optionally narrow by `from` / `to` (`YYYY-MM-DD`, inclusive; `from <= to`) and `store`. A malformed or inverted period returns 400. - [Settle a deposit line](https://docs-pos.solya.app/api-reference/finance/settle-a-deposit-line.md): Records a bank / processor settlement on one line of an open batch, matched by its `reference` (the path `batchId` is the authority — do NOT send it in the body). Returns the updated batch. 404s for an unknown batch or line; 422 once the batch is reconciled. - [Summarise sales into dashboard KPIs](https://docs-pos.solya.app/api-reference/finance/summarise-sales-into-dashboard-kpis.md): Rolls a period's finalized sale tickets up into the dashboard KPIs: ticket count, gross TTC sales, basket average, units sold, VAT total and the top-selling products. Pass `?period=` (e.g. `today` (default) / `all`) and an optional `?store=` to narrow to one store; without a store it aggregates acro… - [Windowed sales analytics report](https://docs-pos.solya.app/api-reference/finance/windowed-sales-analytics-report.md): Rolls the per-ticket sales read model up into a windowed analytics report for the `Rapports / Analytics` screen: the headline KPIs for the `[from, to]` UTC-day window (`YYYY-MM-DD`), a period-over-period comparison against the immediately-preceding equal-length window (absolute Δ + %, `percent` null… - [Export the period retention archive](https://docs-pos.solya.app/api-reference/fiscal/export-the-period-retention-archive.md): Exports the period-sealed NF525 retention archive (JET, G4): the `[from, to]` window's ticket signatures + closures anchored to the pre-window chain, plus the algorithm manifest and published public keys so an auditor re-verifies it OFFLINE. `store` (the chain id) and the `?from=`/`?to=` UTC-day win… - [Export the signed fiscal journal](https://docs-pos.solya.app/api-reference/fiscal/export-the-signed-fiscal-journal.md): Exports a register chain's full, ordered signature journal plus its FRESHLY recomputed integrity verdict (tamper / gap / broken-link detection). `store` (the chain id) is REQUIRED; without it the route 400s. An empty chain exports an empty, vacuously-valid journal. This is the inalterable archive an… - [Fiscal X (mid-shift read)](https://docs-pos.solya.app/api-reference/fiscal/fiscal-x-mid-shift-read.md): The same figures as the Z (turnover by tender, VAT breakdown, counts, perpetual grand total) but mid-shift and NON-closing — this route writes nothing and never closes a session. `store` (the chain id) is REQUIRED; a missing store or a malformed `day` 400s. Pass an optional `?day=` UTC calendar day… - [Fiscal Z (closing report)](https://docs-pos.solya.app/api-reference/fiscal/fiscal-z-closing-report.md): Rolls a register chain's period up into the fiscal Z figures: turnover by tender, the VAT breakdown by rate, the sales/refunds counts and the PERPETUAL grand total (Σ of every signed total in the chain). `store` (the chain id — chains are per store) is REQUIRED; without it, or with a malformed `day`… - [Get one sealed closure by period](https://docs-pos.solya.app/api-reference/fiscal/get-one-sealed-closure-by-period.md): Reads one sealed closure selected by `?kind=` + `?period=`. `store` (the chain id) is REQUIRED; without it the route 400s, and a period that is not yet closed 404s. - [List a store's sealed closures](https://docs-pos.solya.app/api-reference/fiscal/list-a-stores-sealed-closures.md): Lists a register chain's sealed closures, ascending by sequence, optionally filtered by `?kind=` (`daily` / `monthly` / `annual`). `store` (the chain id) is REQUIRED; without it the route 400s. - [List the published fiscal verification keys](https://docs-pos.solya.app/api-reference/fiscal/list-the-published-fiscal-verification-keys.md): Returns the Ed25519 PUBLIC keys the NF525 fiscal signature chain is sealed with, so an auditor can verify that chain OFFLINE with no secret: take a record's key id, fetch the matching `publicKeyPem` here, recompute the link's canonical body and check the signature. Unauthenticated on purpose — a pub… - [Query the central audit log](https://docs-pos.solya.app/api-reference/fiscal/query-the-central-audit-log.md): Lists the network's recorded sensitive actions, most recent first, optionally narrowed by `?actorId=`, `?entityType=`, `?entityId=` and/or `?action=`, bounded by ISO-8601 `?from=` / `?to=` instants, and capped by `?limit=` (a positive integer; a malformed limit 400s). Every use-case run is appended… - [Seal a mandatory fiscal closure](https://docs-pos.solya.app/api-reference/fiscal/seal-a-mandatory-fiscal-closure.md): Seals a period `{ store, kind, period }` into the register's closure chain as its own sequenced, chain-linked fiscal event (NF525 G3). `store` (the chain id), `kind` (`daily` / `monthly` / `annual`) and the matching `period` key (`YYYY-MM-DD` / `YYYY-MM` / `YYYY`) are all REQUIRED — a missing store… - [Verify the fiscal chain integrity](https://docs-pos.solya.app/api-reference/fiscal/verify-the-fiscal-chain-integrity.md): Verifies a register chain end to end (tamper / sequence-gap / broken-link detection), returning `{ valid, length }` and, on a break, the `brokenAt` sequence and the `reason`. `store` (the chain id) is REQUIRED; without it the route 400s, and a store with no chain yet 404s. - [Bulk-issue stored-value instruments](https://docs-pos.solya.app/api-reference/instruments/bulk-issue-stored-value-instruments.md): Mints many instruments from a batch of drafts through the SAME issue path. Each element of `instruments` is exactly an `issueGiftcard` body — `id`, `kind` (`gift_card` | `credit_note` | `store_credit`), `code`, 3-letter `currency` and a strictly positive integer `amountCents`, plus optional `custome… - [Get an instrument by id](https://docs-pos.solya.app/api-reference/instruments/get-an-instrument-by-id.md): Returns one instrument's back-office read model, addressed by the INTERNAL id (not the bearer code). Reach for this when you already hold an id from the listing or from an issuance; if all you have is a scanned card, use the by-code lookup. 404s when no instrument carries the id. - [Get an instrument by its bearer code](https://docs-pos.solya.app/api-reference/instruments/get-an-instrument-by-its-bearer-code.md): Resolves the bearer code printed/encoded on a card to its live instrument (status, currency, remaining `balanceCents`, expiry). This is the lookup to run BEFORE redeeming or voiding: it tells you whether the card is `active`, unexpired and worth what the holder claims. 404s when no instrument carrie… - [Issue a stored-value instrument](https://docs-pos.solya.app/api-reference/instruments/issue-a-stored-value-instrument.md): Mints ONE instrument at `amountCents` (integer cents, strictly positive) under a caller-chosen `id` and bearer `code`, both of which must be unused. `kind` picks the product: `gift_card` (prepaid bearer), `credit_note` (issued in lieu of a cash refund) or `store_credit` (a named account balance) — t… - [List stored-value instruments](https://docs-pos.solya.app/api-reference/instruments/list-stored-value-instruments.md): Returns one page of the issued instrument book (gift cards, credit notes and store credit share one aggregate). Filter with `kind` and/or `status`, sort by `code` or `balanceCents`, and walk with `page`/`pageSize` (max 100) until `pageCount`. Use this to survey or reconcile the book; to resolve ONE… - [Redeem value from an instrument](https://docs-pos.solya.app/api-reference/instruments/redeem-value-from-an-instrument.md): Draws `amountCents` from the instrument identified by its BEARER CODE and returns the instrument at its reduced balance (`depleted` once it reaches zero). Keyed by code, not id, because that is what the till physically has. IRREVERSIBLE — there is no un-redeem verb; check the balance with the by-cod… - [Reload an instrument with more value](https://docs-pos.solya.app/api-reference/instruments/reload-an-instrument-with-more-value.md): Adds `amountCents` to the instrument addressed by the path id, reactivating it when it had been drawn to `depleted`. `initialBalanceCents` is deliberately left at the ISSUANCE value, so a reloaded card ends up with `balanceCents` ABOVE it — which drops the card out of the breakage report's `neverRed… - [Report stored-value breakage over a capped sample](https://docs-pos.solya.app/api-reference/instruments/report-stored-value-breakage-over-a-capped-sample.md): Aggregates unredeemable and untouched stored value AS OF THE REQUEST CLOCK: `expired*` counts instruments past their `expiresAt` that still carry a balance, `neverRedeemed*` counts live instruments never drawn on, and `total*` sums both. Voided instruments are excluded. ⚠️ NOT A NETWORK TOTAL: the u… - [Void an instrument](https://docs-pos.solya.app/api-reference/instruments/void-an-instrument.md): Cancels the instrument addressed by the path id, whatever balance remains on it — a supervisor-level, IRREVERSIBLE destruction of a customer's stored value with no un-void verb. The request takes no body. Reach for it only for a lost, fraudulent or mis-issued card; to consume value against a sale, r… - [Configure a connector](https://docs-pos.solya.app/api-reference/integrations/configure-a-connector.md): MERGES the submitted `config` patch into the connector's stored config and returns the connector (secrets re-masked). Only the fields you send are touched; omitted fields are left as they were. A field set to the mask sentinel (`••••••`) is SKIPPED — echoing a masked secret back keeps the stored one… - [Disable a connector](https://docs-pos.solya.app/api-reference/integrations/disable-a-connector.md): Turns the connector OFF (sets `enabled: false`) and returns it (secrets masked). Idempotent — disabling an already-disabled connector is a no-op success. Reversible: the stored config is untouched, so re-enabling restores the connector as configured. 404 on an unknown key. Requires `pos.settings.man… - [Enable a connector](https://docs-pos.solya.app/api-reference/integrations/enable-a-connector.md): Turns the connector ON (sets `enabled: true`) and returns it (secrets masked). Idempotent — enabling an already-enabled connector is a no-op success. A bounded, reversible toggle; it does NOT push credentials (configure those with the update operation first). 404 on an unknown key. Requires `pos.set… - [List the connectors](https://docs-pos.solya.app/api-reference/integrations/list-the-connectors.md): Returns the whole connector catalogue the back-office 'Intégrations' hub steers: payment terminals, e-commerce storefronts, accounting exports and merchandising sync, each with its `key`, display `name`, `category`, `enabled` toggle and `config` map. SECRETS ARE MASKED: every credential-looking conf… - [Read one connector](https://docs-pos.solya.app/api-reference/integrations/read-one-connector.md): Returns a single connector addressed by its stable `key` (the value from the list), with its `config` secrets masked (`••••••`). 404 when no connector carries the key. Read this before an update: the update MERGES your patch into the config, so start from the fields you see here. - [Approve a stock write-off](https://docs-pos.solya.app/api-reference/inventory/approve-a-stock-write-off.md): Approves a `pending` write-off and projects its removal batch onto perpetual on-hand through the shared stock-movement seam (the same one sales/returns/counts use). 404s for an unknown write-off; 422s when it is not `pending` (already decided). - [Close a count session](https://docs-pos.solya.app/api-reference/inventory/close-a-count-session.md): Closes an open session and returns the valued adjustment batch it emits (one signed delta per SKU whose count differs from book, each reasoned `shrinkage` or `overage`). The batch is what projects onto perpetual on-hand. 404s for an unknown session; 422s when the session is already closed. - [Complete a count task](https://docs-pos.solya.app/api-reference/inventory/complete-a-count-task.md): Marks a due task counted: resets the SKU's last-counted anchor to now (a full cadence reset), so the next count falls a whole cadence period out. The class + anchor are resolved from the stored policy — only `storeId` (+ optional `expectedVersion`) travel. 404s when no policy exists for the SKU in t… - [Get a count session's valued variance](https://docs-pos.solya.app/api-reference/inventory/get-a-count-sessions-valued-variance.md): Returns the valued (book vs counted) variance of one physical count session: a per-line delta valued in integer cents, plus the shrinkage / overage totals. Read it after recording lines to preview the adjustment a close would emit. 404s for an unknown session id. - [Get a stock item by id](https://docs-pos.solya.app/api-reference/inventory/get-a-stock-item-by-id.md): Returns the stock read model for one inventory line (a `sku × shop` position). 404s when no stock line carries the given id. - [List cadence configs](https://docs-pos.solya.app/api-reference/inventory/list-cadence-configs.md): Returns every store's per-class cadence plan (which velocity classes A/B/C are counted, and how many whole days between counts). This is the authored schedule, not the due tasks — for those call the plan operation. - [List stock items](https://docs-pos.solya.app/api-reference/inventory/list-stock-items.md): Returns one page of the stock read model (on-hand / reserved / reorder point, valued in cents), optionally filtered by derived `status` (in-stock/low-stock/out-of-stock) or `category` and sorted. Use `page`/`pageSize` (max 100) to walk the result; `total`/`pageCount` tell you when to stop. - [List stock write-offs](https://docs-pos.solya.app/api-reference/inventory/list-stock-write-offs.md): Returns the write-off history newest-first, optionally narrowed by `storeId` and/or approval `status`. An unrecognised status filter is ignored rather than rejected. This is an unpaginated array. - [Open a count session](https://docs-pos.solya.app/api-reference/inventory/open-a-count-session.md): Opens a physical inventory count for one shop from a seeded set of lines (each a SKU with its book quantity and unit cost in cents). Every line starts uncounted (`countedQuantity: null`); record counts against it, then close to emit the valued adjustment. 409s when the session id already exists. - [Plan a store's due cycle counts](https://docs-pos.solya.app/api-reference/inventory/plan-a-stores-due-cycle-counts.md): Derives the ordered, due count tasks for one store from its cadence config and per-SKU policies: each task carries its class, cadence, last-counted anchor and an urgency trail (elapsed / overdue days + a priority score), most urgent first. Pass `?storeId=` (required). Hand a due task off to the… - [Record a counted line](https://docs-pos.solya.app/api-reference/inventory/record-a-counted-line.md): Records the physically counted quantity for one SKU in an open session (the session id comes from the path). Returns the updated session with that line's `countedQuantity` set. 404s for an unknown session; 422s once the session is closed. - [Record a stock write-off](https://docs-pos.solya.app/api-reference/inventory/record-a-stock-write-off.md): Records a `pending` stock write-off (a reason code plus valued lines) for later approval. The server mints the record id — do not send one. Recording emits NO stock movement; on-hand is only touched once the write-off is approved. - [Reject a stock write-off](https://docs-pos.solya.app/api-reference/inventory/reject-a-stock-write-off.md): Rejects a `pending` write-off. No stock movement is emitted — a rejected loss never touches on-hand. 404s for an unknown write-off; 422s when it is not `pending`. - [Set a SKU's count policy](https://docs-pos.solya.app/api-reference/inventory/set-a-skus-count-policy.md): Seeds or updates one SKU's count policy (its velocity class + last-counted anchor). `expectedVersion` is enforced only when the record already exists (optimistic concurrency). Returns the policy identity with the bumped version. - [Skip a count task](https://docs-pos.solya.app/api-reference/inventory/skip-a-count-task.md): Passes a due task over this cycle: defers the SKU's anchor FORWARD by one cadence period (not to now), so it re-surfaces next cycle rather than immediately. The class + anchor are resolved from the stored policy. 404s when no policy exists for the SKU in that store. - [Upsert a store's cadence config](https://docs-pos.solya.app/api-reference/inventory/upsert-a-stores-cadence-config.md): Upserts one store's per-class cadence table (a store has exactly one config; posting REPLACES it). Each rule maps a velocity class (A/B/C) to a strictly-positive whole-day interval. Returns the saved config. - [Accrue loyalty points for a sale](https://docs-pos.solya.app/api-reference/loyalty/accrue-loyalty-points-for-a-sale.md): Appends an EARN entry to a customer's ledger for a settled sale. `subtotalCents` is the sale subtotal in integer cents; the points granted follow the active program's `accrualPointsPerCent`. `entryId` is the IDEMPOTENCY KEY: supply the sale's own stable id and a replay returns 409 instead of double-… - [Get a customer's derived loyalty account](https://docs-pos.solya.app/api-reference/loyalty/get-a-customers-derived-loyalty-account.md): Recomputes a CUSTOMER's loyalty standing from the ledger: the `balance` redeemable right now (expiry-aware when the program config sets an expiry policy), the monotonic `lifetimePoints`, and the tier those lifetime points resolve to under the active program. This is the authoritative number to quote… - [Get a loyalty member by id](https://docs-pos.solya.app/api-reference/loyalty/get-a-loyalty-member-by-id.md): Returns one row of the loyalty member directory. The path takes a MEMBER id (as returned by `listLoyaltyMembers`), not a customer id — for a customer id use `getLoyaltyAccount`. 404s when no member carries the id. - [Get the active loyalty program config](https://docs-pos.solya.app/api-reference/loyalty/get-the-active-loyalty-program-config.md): Returns the loyalty plan the earn/burn maths currently applies: `accrualPointsPerCent` (points granted per cent spent — 0.01 means 1 point per euro), `redemptionCentsPerPoint` (the discount one point buys), the tier ladder ordered by `minLifetimePoints`, and the optional points-expiry policy. Read t… - [List loyalty members](https://docs-pos.solya.app/api-reference/loyalty/list-loyalty-members.md): Returns one page of the loyalty member directory: who is enrolled, their tier label, redeemable `balance` and monotonic `lifetimePoints`. Use it to browse or to find a member id; when you already hold a CUSTOMER id and want the live balance, call `getLoyaltyAccount` instead — that one recomputes fro… - [Redeem loyalty points for a discount](https://docs-pos.solya.app/api-reference/loyalty/redeem-loyalty-points-for-a-discount.md): Appends a BURN entry, converting `points` into a discount worth the program's `redemptionCentsPerPoint` each — the granted value comes back as `valueCents`. Read `getLoyaltyAccount` first and never burn more than its `balance` (422 otherwise). `entryId` is the idempotency key, minted server-side whe… - [Replace the loyalty program config](https://docs-pos.solya.app/api-reference/loyalty/replace-the-loyalty-program-config.md): Upserts the ENTIRE loyalty plan — this is a full replace, not a patch, so send every field including the complete tier ladder (at least one rung; omitted rungs are deleted). GET the current config first and edit that document. The change takes effect immediately for every subsequent accrual, redempt… - [Author a marketing campaign](https://docs-pos.solya.app/api-reference/marketing/author-a-marketing-campaign.md): Creates a campaign targeting a saved RFM segment over one channel. AUTHORING ONLY — nothing is sent here; call `dryRunCampaign` then `sendCampaign` for that. `segment` is the same predicate `getCustomerSegmentation` accepts (`tier` / `minMonetaryCents` / `segment`); an EMPTY object `{}` targets the… - [Get a campaign by id](https://docs-pos.solya.app/api-reference/marketing/get-a-campaign-by-id.md): Returns one campaign: its authored fields plus the live `status` and the `audienceCount` / `recipientCount` / `sentCount` / `failedCount` recorded at its last dispatch. Poll this after `sendCampaign` to observe the outcome. 404s for an unknown id. - [List marketing campaigns](https://docs-pos.solya.app/api-reference/marketing/list-marketing-campaigns.md): Returns every authored campaign, newest first, with its lifecycle `status` (`draft`, `scheduled`, `sending`, `sent`, `failed`) and the delivery counters recorded at its last dispatch. This is a BARE ARRAY, not a page envelope — there is no pagination. Use it to find a campaign id before a dry-run or… - [Preview a campaign's recipients without sending](https://docs-pos.solya.app/api-reference/marketing/preview-a-campaigns-recipients-without-sending.md): Resolves the campaign's audience from its saved segment, filters it by per-channel consent (`marketing_email` for email, `marketing_sms` for SMS) and a usable contact, and returns the resulting plan — WITHOUT sending anything and without mutating the campaign. ALWAYS run this before `sendCampaign`:… - [Send a campaign to its consented audience](https://docs-pos.solya.app/api-reference/marketing/send-a-campaign-to-its-consented-audience.md): DELIVERS the campaign: it re-resolves the plan and hands every eligible recipient to the ESP. This reaches real customers and CANNOT be undone — run `dryRunCampaign` first and only send on an explicit human instruction. The response carries `dryRun`: when no ESP key is provisioned it is `true` and N… - [Create a region](https://docs-pos.solya.app/api-reference/network/create-a-region.md): Adds a geographic region to the network directory. This is a back-office MAINTENANCE operation: the created region immediately becomes a selectable grouping stores can be assigned to. The `id` is caller-supplied — pick a stable, URL-safe slug (e.g. `reg-bre`), because it is the handle every other ma… - [Deactivate (archive) a region](https://docs-pos.solya.app/api-reference/network/deactivate-archive-a-region.md): Soft-archives a region by flipping its `active` flag to `false` — never a physical delete (historic stores still reference the region label), so it still reads back as inactive and can be reactivated with an update. Idempotent: deactivating an already-inactive region is a no-op that returns it uncha… - [Deactivate (close) a store](https://docs-pos.solya.app/api-reference/network/deactivate-close-a-store.md): Soft-closes a store by flipping its `active` flag to `false` — never a physical delete (historic sales, transfers and fiscal reports still reference it), so the store still reads back as inactive and can be reopened with an update. This is the safe way to take a location out of the trading network:… - [Get a paired device by id](https://docs-pos.solya.app/api-reference/network/get-a-paired-device-by-id.md): Resolves one paired peripheral from the id you took out of the fleet listing. Reach for it to re-check a single device's `status` and `lastSeen` after an operator power-cycles it, rather than re-listing the whole fleet. `lastSeen` is the ISO-8601 instant of the device's most recent state change, not… - [Get a region by id](https://docs-pos.solya.app/api-reference/network/get-a-region-by-id.md): Resolves one region from the id you took out of the region listing, when you already hold the id and only need its `name`, `code` or `storeCount` — otherwise list and filter, which is one call instead of two. Reach for it to confirm a region exists and read its current fields before a maintenance wr… - [Get a store by id](https://docs-pos.solya.app/api-reference/network/get-a-store-by-id.md): Resolves one store from the slug id you took out of the store listing. Reach for it to confirm a store exists and is still `active` before addressing it in a store-scoped operation, or to read the `city`/`region` it belongs to. 404s when no store carries the given id — treat that as 'this store slug… - [List the network's regions](https://docs-pos.solya.app/api-reference/network/list-the-networks-regions.md): Returns one page of the regions the store network is grouped into — the coarsest level of the network hierarchy (region → store → register). Reach for it to answer 'where does this network operate' or to resolve a region a user named in prose before drilling into stores. JOINING TO STORES: a store d… - [List the network's stores](https://docs-pos.solya.app/api-reference/network/list-the-networks-stores.md): Returns one page of the store directory. START HERE when a task mentions a shop, a branch or a location: the `id` of each row is the store slug every store-scoped operation takes downstream — store-price overrides, inventory and count sessions, stock transfers, cash sessions, fiscal reports and the… - [List the paired register peripherals](https://docs-pos.solya.app/api-reference/network/list-the-paired-register-peripherals.md): Returns one page of the hardware paired onto the network's POS registers — this is the answer to 'is the till equipment working' and 'which registers exist'. Each row is ONE peripheral, not one register, so a single register appears several times (once per printer / scanner / terminal / drawer / dis… - [Pair a device onto a register](https://docs-pos.solya.app/api-reference/network/pair-a-device-onto-a-register.md): Registers a new peripheral against a store's register. This is an ONBOARDING operation performed while someone is physically installing hardware — it records the pairing, it does not connect to the device, so the paired row is bookkeeping until the till itself reports a link. The `id` is caller-supp… - [Provision a store](https://docs-pos.solya.app/api-reference/network/provision-a-store.md): Adds a store to the network directory. This is an ONBOARDING operation, not an everyday one: the created store immediately becomes addressable for pricing, inventory, transfers and register pairing, so only call it when the task is explicitly about opening a location. The `id` is caller-supplied — p… - [Update a paired device](https://docs-pos.solya.app/api-reference/network/update-a-paired-device.md): Replaces a paired peripheral's fields WHOLESALE — this is not a patch. ALWAYS read the device first, apply your change to the object you got back, and send the whole thing. An omitted field does not keep its stored value: `id`, `label`, `kind`, `store` and `register` are required (omitting one is a… - [Update a region](https://docs-pos.solya.app/api-reference/network/update-a-region.md): Replaces a region's directory fields WHOLESALE — this is not a patch. ALWAYS read the region first, apply your change to the object you got back, and send the whole thing. An omitted field does not keep its stored value: `id`, `name` and `code` are required (omitting one is a 400), `storeCount` defa… - [Update a store](https://docs-pos.solya.app/api-reference/network/update-a-store.md): Replaces a store's directory fields WHOLESALE — this is not a patch. ALWAYS read the store first, apply your change to the object you got back, and send the whole thing. An omitted field does not keep its stored value: `id`, `name`, `city` and `region` are required (omitting one is a 400), and `acti… - [Get per-channel notification availability](https://docs-pos.solya.app/api-reference/notifications/get-per-channel-notification-availability.md): Reports whether e-mail and SMS may be used for a transactional send right now, folding the network settings, the credit wallet and the current-period usage meter into one verdict. ALWAYS call this before `sendSaleReceipt` — it is the only free way to learn that a send would be refused, and the calle… - [Send a finalized sale's receipt to the customer](https://docs-pos.solya.app/api-reference/notifications/send-a-finalized-sales-receipt-to-the-customer.md): Delivers the receipt for one FINALIZED sale to a real person over `email` or `sms`. This leaves the system: it hands the message to the ESP and, for SMS, DEBITS the account credit wallet. It cannot be recalled and there is no delete endpoint, so only send on an explicit request naming the sale and t… - [Advance an order](https://docs-pos.solya.app/api-reference/orders/advance-an-order.md): Advances an order along its lifecycle: `fulfil` an `accepted` order to `fulfilled`, or `cancel` a `captured` / `accepted` order. The order `id` comes from the PATH — a body `orderId` is ignored. Failure conditions: 400 on a malformed body; 404 for an unknown order; 422 on an illegal transition (e.g.… - [Capture an order](https://docs-pos.solya.app/api-reference/orders/capture-an-order.md): Captures an omnichannel order from a channel into the `captured` state, attributed to the actor, with no fulfilling store yet (201). This is the entry point of the OMS write loop — route it next. Failure conditions: 400 on a malformed body; 409 when the order `id` already exists. - [Get an order by id](https://docs-pos.solya.app/api-reference/orders/get-an-order-by-id.md): Returns the full order read model for one order — its lifecycle `status`, the `fulfillingStoreId` (null until routed), the customer and the ordered lines. 404s when no order carries the given id. - [List orders](https://docs-pos.solya.app/api-reference/orders/list-orders.md): Returns one page of the omnichannel order read model, optionally filtered by `status` and `channel` and sorted (`capturedAt` / `total` / `id`). Use `page`/`pageSize` (max 100) to walk the result; `total`/`pageCount` tell you when to stop. Reach for it to browse the OMS backlog. - [Revert an order one step](https://docs-pos.solya.app/api-reference/orders/revert-an-order-one-step.md): Steps an order one step BACK along the forward lifecycle — the safe undo for a mis-click: `fulfilled → accepted`, or `accepted → captured` (clearing the fulfilling store). Takes no body; the order `id` comes from the PATH. Failure conditions: 404 for an unknown order; 422 for a status that cannot be… - [Route a captured order](https://docs-pos.solya.app/api-reference/orders/route-a-captured-order.md): Routes a `captured` order to a fulfilling store chosen deterministically from the supplied `candidates` (lowest `rank`, then smallest `storeId`, among those holding enough stock), moving it to `accepted`. When no candidate can fully fulfil it, the order moves to the terminal `rejected` state instead… - [Create a purchase order](https://docs-pos.solya.app/api-reference/procurement/create-a-purchase-order.md): Opens a new purchase order for a supplier + shop with the ordered per-SKU quantities and their unit cost in cents. The order starts `open` with every line unreceived. The supplier is validated. 404s for an unknown supplier; 409s when the order id already exists. - [Create a supplier](https://docs-pos.solya.app/api-reference/procurement/create-a-supplier.md): Creates one supplier (name, category, contact email, replenishment lead time in days). `active` defaults to true. 409s when a supplier with the same id already exists. - [Credit a return-to-vendor](https://docs-pos.solya.app/api-reference/procurement/credit-a-return-to-vendor.md): Credits a `shipped` RTV, reconciling the expected supplier credit (no body). 404s for an unknown RTV; 422s when it is not `shipped`. - [Deactivate a supplier](https://docs-pos.solya.app/api-reference/procurement/deactivate-a-supplier.md): Soft-archives a supplier by flipping `active` to false — never a physical delete, so it still reads back (as inactive). Idempotent-ish: re-deactivating stays inactive. 404s for an unknown supplier. - [Get a purchase order by id](https://docs-pos.solya.app/api-reference/procurement/get-a-purchase-order-by-id.md): Returns one purchase order with its status and lines. 404s for an unknown id. - [Get a return-to-vendor by id](https://docs-pos.solya.app/api-reference/procurement/get-a-return-to-vendor-by-id.md): Returns one RTV with its status, lines and lifecycle timestamps. 404s for an unknown id. - [Get a supplier by id](https://docs-pos.solya.app/api-reference/procurement/get-a-supplier-by-id.md): Returns one supplier's read model. 404s when no supplier carries the given id. - [List purchase orders](https://docs-pos.solya.app/api-reference/procurement/list-purchase-orders.md): Returns one page of purchase orders, optionally filtered by `status` (open/received), `supplierId` and/or `shopId`, sorted by `id` or `lineCount`. Use `page`/`pageSize` (max 100) to walk the result; `total`/`pageCount` tell you when to stop. - [List returns-to-vendor](https://docs-pos.solya.app/api-reference/procurement/list-returns-to-vendor.md): Returns the RTV history newest-first, optionally narrowed by `supplierId` and/or `status`. An unrecognised status filter is ignored rather than rejected. This is an unpaginated array. - [List suppliers](https://docs-pos.solya.app/api-reference/procurement/list-suppliers.md): Returns one page of suppliers, optionally filtered by `category` and/or `active` and sorted by `name` or `leadTimeDays`. Use `page`/`pageSize` (max 100) to walk the result; `total`/`pageCount` tell you when to stop. - [Raise a return-to-vendor](https://docs-pos.solya.app/api-reference/procurement/raise-a-return-to-vendor.md): Raises a `draft` return-to-vendor (supplier + reason + valued lines). The server mints the record id — do not send one. Raising emits NO stock movement; on-hand is only touched once the RTV is shipped. - [Receive against a purchase order](https://docs-pos.solya.app/api-reference/procurement/receive-against-a-purchase-order.md): Books a batch of receipts against an OPEN order, accumulating each line's received quantity and re-deriving the order status (`received` once every line is fully received). Re-runs the receiving guard server-side. 404s for an unknown order or receipt SKU; 422s when the order is already fully receive… - [Ship a return-to-vendor](https://docs-pos.solya.app/api-reference/procurement/ship-a-return-to-vendor.md): Ships a `draft` RTV and projects the outbound goods off perpetual on-hand through the shared stock-movement seam. The departing store comes from the body. 404s for an unknown RTV; 422s when it is not `draft`. - [Update a supplier](https://docs-pos.solya.app/api-reference/procurement/update-a-supplier.md): Replaces a supplier's editable fields. The path id is authoritative — any `id` in the body is overwritten, so you cannot retarget the update onto another supplier. 404s for an unknown supplier. - [Apply an authorised discount to a whole ticket](https://docs-pos.solya.app/api-reference/promotions/apply-an-authorised-discount-to-a-whole-ticket.md): Applies a manager-authorised reduction to the WHOLE ticket and persists the traced record. This is the deliberate, one-off human decision — reach for it only when no automatic promotion or presented coupon covers the case, and never to reproduce an offer that should be a rule (`POST /v1/promotions`)… - [Batch-generate a run of coupon codes](https://docs-pos.solya.app/api-reference/promotions/batch-generate-a-run-of-coupon-codes.md): Mints `count` DISTINCT coupons (1–1000) that all share one discount, validity window, `maxRedemptions` and `minBasketCents`, each under a generated code optionally prefixed with `codePrefix`. Use it for one-per-customer mailing or compensation runs where the codes must not be guessable; use `POST /v… - [Create one coupon under a chosen code](https://docs-pos.solya.app/api-reference/promotions/create-one-coupon-under-a-chosen-code.md): Mints ONE promo code with the exact `code` string you choose — use this for a named, shareable code (`SAVE10`, `BLACKFRIDAY`); use `POST /v1/coupons/batch` when you need many unguessable one-per-customer codes instead. The `id` is server-minted and returned; the `code` is what the customer presents.… - [Create or replace an automatic promotion rule](https://docs-pos.solya.app/api-reference/promotions/create-or-replace-an-automatic-promotion-rule.md): UPSERTS one automatic promotion rule by `id`: there is no separate create and update, and no PATCH. Posting an existing id REPLACES that rule wholesale — every field not in your body is destroyed, including the reward mechanics. DANGER: the API exposes NO read-modify-write path for a rule. The only… - [Deactivate a coupon](https://docs-pos.solya.app/api-reference/promotions/deactivate-a-coupon.md): SOFT-ARCHIVES one coupon by its server-minted `id` (not its code — resolve the id through `GET /v1/coupons` first). This is the only way to stop a code: there is no delete, and the coupon stays in the catalogue with `active:false` so its past redemptions remain auditable. Once deactivated it reads a… - [Deactivate a promotion rule](https://docs-pos.solya.app/api-reference/promotions/deactivate-a-promotion-rule.md): Retires one automatic promotion, addressed by the path `id`, by ENDING its validity window now: the till stops applying it immediately and the directory reads it as `expired`. A promotion rule has NO `active` flag — its `[validFrom, validUntil]` window IS its lifecycle — so this is the soft-retire (… - [Edit an existing coupon](https://docs-pos.solya.app/api-reference/promotions/edit-an-existing-coupon.md): REPLACES the terms of one existing coupon addressed by the path `id` (server-minted; resolve it through `GET /v1/coupons` — the `code` is what customers type, the `id` is what this takes). The body is the SAME shape as create: it overwrites `code`, `discount`, the validity window, `maxRedemptions` a… - [Evaluate the active promotion rules against a cart](https://docs-pos.solya.app/api-reference/promotions/evaluate-the-active-promotion-rules-against-a-cart.md): DRY-RUN: loads every rule whose validity window contains the current instant, runs them against the cart snapshot you pass, and returns the best NON-CONFLICTING set of outcomes. Writes nothing and does not touch the cart — it answers 'what would this basket earn automatically?'. Two rules that claim… - [Get a promotion by id](https://docs-pos.solya.app/api-reference/promotions/get-a-promotion-by-id.md): Resolves ONE automatic promotion by its rule id and returns the directory projection: `id`, `name`, `type`, `status`, `validFrom`, `validUntil`. That is the whole payload. It does NOT carry the rule's reward mechanics — no `skuId`, `minQuantity`, `reward`, `components`, `bundlePriceCents` or `buySku… - [Get an applied discount by id](https://docs-pos.solya.app/api-reference/promotions/get-an-applied-discount-by-id.md): Reads back ONE already-applied discount by the `id` the caller chose when applying it — the audit trace, not a configuration. It tells you what was taken off (`amountCents`, SIGNED and `<= 0`), off what gross (`baseCents`), how deep that was (`effectiveBps`), under which coded `reason`, by which `ac… - [List automatic promotion rules](https://docs-pos.solya.app/api-reference/promotions/list-automatic-promotion-rules.md): Browses the catalogue of AUTOMATIC promotion rules — the reductions the till applies on its own when a cart matches, with no promo code and no manager approval. Use this to answer 'what offers are running?', to find a rule's id before reading or re-configuring it, or to audit what is scheduled or ex… - [List the coupon catalogue](https://docs-pos.solya.app/api-reference/promotions/list-the-coupon-catalogue.md): Returns EVERY authored promo code — active and deactivated alike — each with its terms and its `redemptionCount` from the ledger. This is the operation to reach for when you need a coupon's `id` (codes are what customers type, ids are what `POST /v1/coupons/{id}/deactivate` takes), when you want to… - [Preview a coupon against a basket total](https://docs-pos.solya.app/api-reference/promotions/preview-a-coupon-against-a-basket-total.md): READ-ONLY preview: resolves the presented `code`, checks it against the basket at the current instant (validity window, remaining redemptions, `minBasketCents` floor) and returns the discount it WOULD grant, in cents. Writes nothing and consumes no redemption — `POST /v1/checkout/finalize` is what a… - [Update an existing promotion rule](https://docs-pos.solya.app/api-reference/promotions/update-an-existing-promotion-rule.md): REPLACES one existing automatic promotion rule wholesale, addressed by the path `id`. Unlike `POST /v1/promotions` (which upserts), this NEVER creates: an unknown id 404s rather than minting a rule, so it is the safe verb when you mean to edit one that is already live. The path id is authoritative —… - [Flag a rental as overdue](https://docs-pos.solya.app/api-reference/rentals/flag-a-rental-as-overdue.md): Flags an `active` rental whose `period.dueAt` has already elapsed as `overdue`. This is a BOOKKEEPING flip for the returns desk and the `status=overdue` listing: it moves no money, charges no fee, and does not block the return — an `overdue` rental is still returned through `returnRental`, which com… - [Get a rental by id](https://docs-pos.solya.app/api-reference/rentals/get-a-rental-by-id.md): Returns ONE rental: the rented `skuId`, the customer/store, the window (`period.startAt` -> `period.dueAt`, the latter derived server-side as `startAt + days`), the money held (`ratePerDayCents`, `depositAmountCents`, `depositReference`) and the lifecycle `status`. `settlement` is PRESENT only once… - [List rentals](https://docs-pos.solya.app/api-reference/rentals/list-rentals.md): Returns the rental book as a flat array, NEWEST-RENTED FIRST, with no pagination — every matching rental is in one reply. Reach for this to answer 'what is out right now', 'what is late' or to FIND a rental id; when you already hold an id use `getRental`. Narrow with `status` — `active` (unit is out… - [Open a rental](https://docs-pos.solya.app/api-reference/rentals/open-a-rental.md): Opens a rental in the `active` state: the unit leaves the store with the customer until `dueAt`, which the server DERIVES as `startAt + days` (do not send it). `days` is one of the four offered tiers — 1, 3, 7 or 14 — and no other value is accepted. MONEY, read carefully: this endpoint moves NONE. `… - [Return a rental and settle the caution](https://docs-pos.solya.app/api-reference/rentals/return-a-rental-and-settle-the-caution.md): IRREVERSIBLE CLOSE-OUT. Takes the unit back, flips the rental to `returned` (terminal — there is no un-return, no re-open and no way to amend a settlement afterwards) and stamps the settlement. Legal from `active` AND from `overdue`; a second call on an already-`returned` rental is 422. `condition`… - [Declare a repair order unrepairable](https://docs-pos.solya.app/api-reference/repairs/declare-a-repair-order-unrepairable.md): TERMINAL, IRREVERSIBLE AND MONEY-BEARING — do not reach for this on your own judgement; call it only when a human has decided the article cannot be fixed. It flips the order to `unrepairable` from ANY non-terminal state, including `ready`, so a mistargeted call can write off a job that was already r… - [Get a repair order by id](https://docs-pos.solya.app/api-reference/repairs/get-a-repair-order-by-id.md): Returns ONE repair order: the `article` taken in, the customer's `issueDescription`, the money (`quoteAmountCents` quoted, `depositAmountCents` acompte already captured at intake), the promised `expectedPickupDate` and the lifecycle `status`. `updatedAt` is the instant of the LAST transition and equ… - [List repair orders](https://docs-pos.solya.app/api-reference/repairs/list-repair-orders.md): Returns the repair board as a flat array, NEWEST-CREATED FIRST, with no pagination — every matching order is in one reply. Reach for this to answer 'what is in the workshop', 'what is waiting to be collected' or to FIND an order id; when you already hold an id use `getRepairOrder`. Narrow with `stat… - [Mark a repair order ready for pickup](https://docs-pos.solya.app/api-reference/repairs/mark-a-repair-order-ready-for-pickup.md): Advances an `in_workshop` order to `ready` — the repair is finished and the article is waiting at the counter. Send no body; only `updatedAt` and `status` change. This does NOT notify the customer and does NOT take any payment: the outstanding `quoteAmountCents - depositAmountCents` is collected lat… - [Record collection of a repaired article](https://docs-pos.solya.app/api-reference/repairs/record-collection-of-a-repaired-article.md): TERMINAL AND IRREVERSIBLE. Records that the customer has taken the article back, flipping a `ready` order to `collected`. Send no body. MONEY TRAP: this records the handover ONLY — it neither collects the outstanding balance nor verifies that anyone did. That balance is `quoteAmountCents - depositAm… - [Send a repair order to the workshop](https://docs-pos.solya.app/api-reference/repairs/send-a-repair-order-to-the-workshop.md): Advances an `intake` order to `in_workshop` — the technician has picked the job up. Send no body; only `updatedAt` and `status` change. This is the FIRST step and cannot be skipped: calling `markRepairReady` on an `intake` order is a 422, so an order must pass through here even if the repair was ins… - [Take an article in for repair](https://docs-pos.solya.app/api-reference/repairs/take-an-article-in-for-repair.md): Opens a repair order in the `intake` state — the article is now in the store's custody. `article.label` is the only required article field; add `skuId` and `serial` when the unit is identifiable and `purchasedAt` when the original sale date is known. `purchasedAt` is RECORDED ONLY — the server deriv… - [Get a processed return by id](https://docs-pos.solya.app/api-reference/returns/get-a-processed-return-by-id.md): Returns the processed return read model for one return id — the signed refund transaction plus its `refundMethod`, `originalTransactionId` and reason. 404s when no return carries the given id. - [Get a return's cash-drawer pay-out](https://docs-pos.solya.app/api-reference/returns/get-a-returns-cash-drawer-pay-out.md): Resolves the signed cash-drawer pay-out a processed return produced — a NEGATIVE integer-cent movement for a cash refund, or `null` for a non-cash / zero-valued one. This is the figure the back-office reconciles the register against. 404s when no return carries the given id. - [Process a return](https://docs-pos.solya.app/api-reference/returns/process-a-return.md): Processes a refund of selected lines from an original charge transaction, at the price they were sold, and settles the money back through the chosen `refundMethod` (201). Reach for it to refund or exchange goods at the counter. A cash refund debits the store's active register drawer and the returned… - [Read the network settings](https://docs-pos.solya.app/api-reference/settings/read-the-network-settings.md): Returns the network-wide back-office preference document: a flat map of preference key → primitive value (`boolean` for a toggle, `string` for a choice) under `preferences`. These are NETWORK settings, not per-store ones — there is no store parameter, and the same document applies everywhere. Takes… - [Replace the network settings](https://docs-pos.solya.app/api-reference/settings/replace-the-network-settings.md): Upserts the ENTIRE network preference document. This is a full replacement, not a patch: every key you omit is DELETED. Read the settings first, merge your change into the map you got back, and send the whole map — sending only the key you want to change silently wipes the rest of the network's conf… - [Get a team member by id](https://docs-pos.solya.app/api-reference/team/get-a-team-member-by-id.md): Returns ONE staff account's directory record (id, name, email, primary `role` label, `store` scope and the `active` flag). Use it to confirm who you are about to act on before a write, and — because `updateTeamMember` REPLACES the whole record — to read the current values you must send back unchange… - [List team members](https://docs-pos.solya.app/api-reference/team/list-team-members.md): Returns one page of the back-office staff directory: the accounts that can sign into the POS, each with its identity, contact `email`, primary `role` label (`owner`, `manager`, `cashier`, `viewer`, …), the `store` (or whole network) it is scoped to, and whether it is still `active`. Reach for this t… - [Offboard a team member (disable sign-in)](https://docs-pos.solya.app/api-reference/team/offboard-a-team-member-disable-sign-in.md): OFFBOARDS a staff account by flipping its `active` flag to `false`, which DISABLES sign-in for that person — the deliberate, auditable way to lock a departed colleague out without deleting their directory row (historic sales and audit trails still reference it). This REVOKES system access, the mirro… - [Provision a team member](https://docs-pos.solya.app/api-reference/team/provision-a-team-member.md): Adds one staff account to the directory. This PROVISIONS a person who can sign in, so only call it on an explicit instruction naming the individual — never to 'fill in' a directory. Unlike the customer and product creates, `id` is REQUIRED and chosen by YOU: nothing is minted server-side. Pick a sta… - [Replace a team member's directory record](https://docs-pos.solya.app/api-reference/team/replace-a-team-members-directory-record.md): REPLACES a staff account's directory record wholesale. This is NOT a patch, despite the shape: `name`, `email`, `role` and `store` are all REQUIRED, and whatever you send becomes the record. Always `getTeamMember` first and send the current values back for the fields you are not changing — reconstru… - [Cancel a transfer](https://docs-pos.solya.app/api-reference/transfer/cancel-a-transfer.md): Cancels a still-`requested` transfer (no body). Only a `requested` transfer may be cancelled. 404s for an unknown transfer; 422s once it has been shipped/received. - [Get a transfer by id](https://docs-pos.solya.app/api-reference/transfer/get-a-transfer-by-id.md): Returns one transfer with its current status and lines. 404s for an unknown id. - [Get a transfer's receipt discrepancy](https://docs-pos.solya.app/api-reference/transfer/get-a-transfers-receipt-discrepancy.md): Returns the shipped-vs-received reconciliation of a RECEIVED transfer: a per-line signed variance (reasoned `short` or `over`) plus the short/over totals. 404s for an unknown transfer; 422s when the transfer has not been received yet. - [List transfers](https://docs-pos.solya.app/api-reference/transfer/list-transfers.md): Returns one page of transfers, optionally filtered by `status` and/or source/destination store, sorted by `id` or `lineCount`. Use `page`/`pageSize` (max 100) to walk the result; `total`/`pageCount` tell you when to stop. - [Receive a transfer](https://docs-pos.solya.app/api-reference/transfer/receive-a-transfer.md): Receives a `shipped` transfer, stamping each line's received quantity, and returns the computed receipt DISCREPANCY (not the transfer itself). 404s for an unknown transfer/SKU; 422s when the transfer is not `shipped`. - [Request a transfer](https://docs-pos.solya.app/api-reference/transfer/request-a-transfer.md): Opens a new inter-store transfer from a source to a DIFFERENT destination store with the requested per-SKU quantities. The transfer starts `requested`, every line unshipped/unreceived. 409s when the transfer id already exists. - [Ship a transfer](https://docs-pos.solya.app/api-reference/transfer/ship-a-transfer.md): Ships a `requested` transfer, stamping each line's shipped quantity from the body (SKUs must already belong to the transfer). Re-runs the state-machine guard server-side. 404s for an unknown transfer/SKU; 422s when the transfer is not `requested`. - [Overview](https://docs-pos.solya.app/en/getting-started/overview.md): What Solya POS is, who it is for, and how this documentation is organized. - [Solya POS](https://docs-pos.solya.app/en/index.md): The Centrale back-office, the Caisse point-of-sale, and the REST API that connects them. ## OpenAPI Specs - [openapi](https://docs-pos.solya.app/openapi.json)