--- name: backend description: >- Reference and schema documentation for LibDashStore backend service and database models. Use this skill whenever working with backend data models, database schema definitions (articles, categories, companies, entities, manifests, orders, POS terminals), or calling and integrating with LibDashStore API methods and namespaces. --- # Dash API Routes Overview Overview of all 141 API endpoints across all modules. ### Parameter Notation - **Required parameters** have no `?` (e.g. `sku:string`, `categoryId`, `query: si:string`, `body: { name }`). - **Optional parameters** are marked with `?` (e.g. `query: categoryId?:integer`, `track_stock?`, `body?: ...`). - **Path parameters** match `{param}` in the route URL. - **Query parameters** are prefixed with `query: ...`. - **Request bodies** are prefixed with `body: ...` (or `body?: ...` if optional). | Method | Route | Params | Return Type | Summary | |:---|:---|:---|:---|:---| | `POST` | `/article` | `body: { categoryId, name, track_stock? }` | `201 { article: { id, categoryId, name, sku, track_stock } }` | Create article in category | | `DELETE` | `/article/{sku}` | `sku:string, query: cascade?:boolean` | `204 void` | Delete article by SKU | | `GET` | `/article/{sku}` | `sku:string` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Get article by SKU | | `PATCH` | `/article/{sku}` | `sku:string, body: { name?, unitamount?, unitSi?, track_stock? }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Update article by SKU | | `GET` | `/article/{sku}/articlelist` | `sku:string` | `200 { items: { id, articleId, sku, name, count, sort }[] }` | Get Stückliste (bundle items) for an article | | `PUT` | `/article/{sku}/articlelist` | `sku:string, body: { items: { articleId?, sku?: string, count?, sort? }[] }` | `200 { items: object[] }` | Set Stückliste (bundle items) for an article | | `GET` | `/article/{sku}/attributevalue` | `sku:string` | `200 { attributevalues: { id, articleId, attributeId, attributeName, exclusive, attributeValueId, value, sort }[] }` | List article attribute values | | `PUT` | `/article/{sku}/attributevalue` | `sku:string, body: { attributevalues: any[] }` | `200 { attributevalues: { id, articleId, attributeId, attributeName, exclusive, attributeValueId, value, sort }[] }` | Bulk set article attribute values | | `PUT` | `/article/{sku}/brand` | `sku:string, body: { brandId: integer }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Set or clear article brand by SKU | | `PUT` | `/article/{sku}/categories` | `sku:string, body: { categoryIds: integer[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Replace article categories by SKU | | `GET` | `/article/{sku}/children` | `sku:string` | `200 { children: { id, sku, name, fathersort, attributeValueId, attributeValue }[] }` | List child articles of a father article | | `POST` | `/article/{sku}/children` | `sku:string, body: { attributeValueId?, value?, name?, sku?: string }` | `201 { article: { id, categoryId, name, sku, track_stock } }` | Add a child article to a father article | | `DELETE` | `/article/{sku}/children/{childSku}` | `sku:string, childSku:string, query: deleteArticle?:boolean` | `200 { success, deleted }` | Remove a child article from a father article | | `PUT` | `/article/{sku}/eans` | `sku:string, body: { eans: string[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Replace article EANs by SKU | | `POST` | `/article/{sku}/father` | `sku:string, body: { isFather, attributeNameId? }` | `200 { article: { id, categoryId, name, sku, track_stock } }` | Toggle father mode for an article | | `GET` | `/article/{sku}/history` | `sku:string, query: limit?:integer` | `200 { history: { id, date, text }[], truncated }` | Get article history by SKU | | `DELETE` | `/article/{sku}/image/{fullHash}` | `sku:string, fullHash:string` | `204 void` | Delete article image | | `PUT` | `/article/{sku}/images/order` | `sku:string, body: { fullHashes: string[] }` | `200 { fullHashes: string[] }` | Reorder article images | | `GET` | `/article/{sku}/optionslist` | `sku:string` | `200 { options: { id, articleId, sku, name, count, sort, mandated }[] }` | Get options list for an article | | `PUT` | `/article/{sku}/optionslist` | `sku:string, body: { options: { articleId?, sku?: string, count?, sort?, mandated? }[] }` | `200 { options: object[] }` | Set options list for an article | | `PUT` | `/article/{sku}/prices` | `sku:string, body: { prices: { price, tax, minmultiplier? }[] }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Replace POS prices by SKU | | `POST` | `/article/{sku}/print` | `sku:string, body: { templateId, printerId, quantity }` | `200` | Print article label | | `GET` | `/article/{sku}/property` | `sku:string` | `200 { properties: { id, articleId, propertyId, name, exclusive, value, sort }[] }` | List article properties | | `PUT` | `/article/{sku}/property` | `sku:string, body: { properties: { propertyId, value, sort? }[] }` | `200 { properties: { id, articleId, propertyId, name, exclusive, value, sort }[] }` | Bulk set article properties | | `DELETE` | `/article/{sku}/property/{propertyId}` | `sku:string, propertyId:integer` | `200` | Delete article property | | `GET` | `/article/{sku}/supplier` | `sku:string` | `200 { suppliers: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price }[] }` | List article suppliers | | `POST` | `/article/{sku}/supplier` | `sku:string, body: { entityId, sku?: string, pu?, stock?, sort?, netPrice?, taxId?, taxRate? }` | `201 { supplier: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price } }` | Assign supplier to article | | `PUT` | `/article/{sku}/supplier/order` | `sku:string, body: { ids: integer[] }` | `200 { ids: integer[] }` | Reorder article suppliers | | `DELETE` | `/article/{sku}/supplier/{id}` | `sku:string, id:integer` | `204 void` | Remove supplier assignment from article | | `PATCH` | `/article/{sku}/supplier/{id}` | `sku:string, id:integer, body: { sku?: string, pu?, stock?, sort?, netPrice?, taxId?, taxRate? }` | `200 { supplier: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price } }` | Update article supplier assignment | | `PUT` | `/article/{sku}/track_stock` | `sku:string, body: { track_stock: boolean }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Set article track_stock flag by SKU | | `PUT` | `/article/{sku}/weight` | `sku:string, body: { weight: number }` | `200 { article: { id, sku, name, slug, track_stock, unitamount, weight, unit, brand, categoryIds: integer[], photos: object[], eans: string[], prices: object[], suppliers: object[] } }` | Set article weight by SKU | | `GET` | `/articleIndex` | — | `200 { articles: { id, sku, name, eans: string[], categoryIds: integer[] }[] }` | List article search index | | `GET` | `/attributename` | — | `200 { attributenames: { id, name, sort, exclusive, values: { id, attributeId, value, sort }[] }[] }` | List attribute names | | `POST` | `/attributename` | `body: { name, sort?, exclusive? }` | `201 { attributename: { id, name, sort, exclusive, values: { id, attributeId, value, sort }[] } }` | Create attribute name | | `PUT` | `/attributename/order` | `body: { attributenameIds: integer[] }` | `200` | Reorder attribute names | | `GET` | `/attributename/{attributeId}/value` | `attributeId:integer` | `200 { values: { id, attributeId, value, sort }[] }` | List values for an attribute | | `POST` | `/attributename/{attributeId}/value` | `attributeId:integer, body: { value, sort? }` | `201 { attributevalue: { id, attributeId, value, sort } }` | Create value for an attribute | | `PUT` | `/attributename/{attributeId}/value/order` | `attributeId:integer, body: { attributevalueIds: integer[] }` | `200` | Reorder values of an attribute | | `DELETE` | `/attributename/{id}` | `id:integer` | `200` | Delete attribute name | | `PATCH` | `/attributename/{id}` | `id:integer, body: { name?, sort?, exclusive? }` | `200 { attributename: { id, name, sort, exclusive, values: { id, attributeId, value, sort }[] } }` | Update attribute name | | `DELETE` | `/attributevalue/{id}` | `id:integer` | `200` | Delete attribute value | | `PATCH` | `/attributevalue/{id}` | `id:integer, body: { value?, sort? }` | `200 { attributevalue: { id, attributeId, value, sort } }` | Update attribute value | | `POST` | `/auth/login` | `body: { idToken: string }` | `200 { message, user }` | Login with Google ID token | | `POST` | `/auth/logout` | — | `200 { message: string }` | Logout | | `GET` | `/brand` | — | `200 { brands: { id, name, gsprpinfo, pics: { id, sort, fullHash, thumbW, thumbH, thumbHash }[] }[] }` | List brands | | `PUT` | `/brand` | `body: { name, gsprpinfo? }` | `200 { brand: { id, name, gsprpinfo, pics: { id, sort, fullHash, thumbW, thumbH, thumbHash }[] } }` | Upsert brand | | `DELETE` | `/brand/{id}` | `id:integer` | `204 void` | Delete brand | | `POST` | `/category` | `body: { parentId, name }` | `201 { category: { id, parentId, sort, name } }` | Create category | | `PUT` | `/category/order` | `body: { parentId, categoryIds: integer[] }` | `200 { categoryIds: integer[] }` | Reorder sibling categories | | `GET` | `/category/tree` | — | `200 { languageId, tree: object[], articles: object[] }` | Category tree | | `DELETE` | `/category/{id}` | `id:integer` | `204 void` | Delete category | | `PATCH` | `/category/{id}` | `id:integer, body: { name?, parentId? }` | `200 { category: { id, name, slug, parentId, sort } }` | Update category (rename or move) | | `GET` | `/category/{id}/articles` | `id:integer` | `200 { articles: { id, sku, name, slug, net, taxRate, track_stock, optionsCount, articleListCount, childCount, fullHash, thumbW, thumbH, thumbHash, brand }[] }` | Articles in category | | `GET` | `/category/{id}/attributevalue` | `id:integer` | `200 { attributevalues: { id, categoryId, attributeId, attributeName, exclusive, attributeValueId, value, sort }[] }` | List category attribute values | | `PUT` | `/category/{id}/attributevalue` | `id:integer, body: { attributevalues: any[] }` | `200 { attributevalues: { id, categoryId, attributeId, attributeName, exclusive, attributeValueId, value, sort }[] }` | Bulk set category attribute values | | `DELETE` | `/category/{id}/image` | `id:integer` | `200 { category: { id, thumbW, thumbH, thumbHash } }` | Delete category image | | `GET` | `/category/{id}/property` | `id:integer` | `200 { properties: { id, categoryId, propertyId, name, exclusive, value, sort }[] }` | List category properties | | `PUT` | `/category/{id}/property` | `id:integer, body: { properties: { propertyId, value, sort? }[] }` | `200 { properties: { id, categoryId, propertyId, name, exclusive, value, sort }[] }` | Bulk set category properties | | `DELETE` | `/category/{id}/property/{propertyId}` | `id:integer, propertyId:integer` | `200` | Delete category property | | `GET` | `/company` | — | `200 { companies: { id, iso639, name, taxrate, reducedtaxrate }[] }` | List companies | | `GET` | `/company/setting` | — | `200 { settings: { key, value }[] }` | List company settings | | `GET` | `/company/setting/{key}` | `key:string` | `200 { setting: { key, value } }` | Get company setting by key | | `PUT` | `/company/setting/{key}` | `key:string, body: { value, frontend? }` | `200 { setting: { key, value } }` | Upsert company setting | | `PUT` | `/company/{id}` | `id:integer, body: { iso639, name, taxrate, reducedtaxrate }` | `200 { company: { id, iso639, name, taxrate, reducedtaxrate } }` | Update company | | `GET` | `/customergroup` | — | `200 { customergroups: { id, name, sort, editable }[] }` | List customer groups | | `POST` | `/customergroup` | `body: { name: string }` | `201 { customergroup: { id, name, sort } }` | Create customer group | | `PUT` | `/customergroup/order` | `body: { customergroupIds: integer[] }` | `200 { customergroupIds: integer[] }` | Reorder customer groups | | `DELETE` | `/customergroup/{id}` | `id:integer` | `204 void` | Delete customer group | | `PATCH` | `/customergroup/{id}` | `id:integer, body: { name: string }` | `200 { customergroup: { id, name, sort } }` | Update customer group | | `GET` | `/delivery` | — | `200 { deliveries: { id, number, type, supplierId, externalNumber, date, createdAt, ledger }[] }` | List deliveries | | `POST` | `/delivery` | `body: { externalNumber, date, lines: { amount, net, taxrate, sku?: string, name?, pu?, rebate?, comment? }[], supplierId?, files?: { mimetype, name, content, sort?, size?, hash?, created?, modified?, meta? }[] }` | `201 { delivery: { id, number, type, supplierId, externalNumber, date, createdAt, ledger, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[], files: { id, manifestId, fileId, sort, hash, mimetype, name, size, created, modified, thumbavif, thumbx, thumby, meta }[] } }` | Create delivery | | `DELETE` | `/delivery/{id}` | `id:integer` | `204 void` | Delete delivery | | `GET` | `/delivery/{id}` | `id:integer` | `200 { delivery: { id, number, type, supplierId, externalNumber, date, createdAt, ledger, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[], files: { id, manifestId, fileId, sort, hash, mimetype, name, size, created, modified, thumbavif, thumbx, thumby, meta }[] } }` | Get delivery | | `PATCH` | `/delivery/{id}` | `id:integer, body: { externalNumber?, date?, supplierId?, lines?: { amount, net, taxrate, sku?: string, name?, pu?, rebate?, comment? }[], files?: { mimetype, name, content, sort?, size?, hash?, created?, modified?, meta? }[] }` | `200 { delivery: { id, number, type, supplierId, externalNumber, date, createdAt, ledger, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[], files: { id, manifestId, fileId, sort, hash, mimetype, name, size, created, modified, thumbavif, thumbx, thumby, meta }[] } }` | Update delivery | | `GET` | `/delivery/{id}/file/{fileId}` | `id:integer, fileId:integer, query: download?:boolean` | `200 string` | Get delivery attachment file content | | `GET` | `/entity` | `query: customergroupId?:integer, role?:string` | `200 { entities: { id, customergroupId, firstName, name, number, createdAt, updatedAt }[] }` | List entities | | `POST` | `/entity` | `body: { customergroupId, name, firstName?, number? }` | `201 { entity: { id, customergroupId, firstName, name, number, createdAt, updatedAt } }` | Create entity | | `GET` | `/entity/next-number` | — | `200 { number: string }` | Peek next customer number | | `GET` | `/entity/{entityId}/address` | `entityId:integer` | `200 { addresses: { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType }[] }` | List entity addresses | | `POST` | `/entity/{entityId}/address` | `entityId:integer, body: { addressType, firstName?, name?, street?, streetNumber?, zip?, city?, county? }` | `201 { address: { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType } }` | Create entity address | | `DELETE` | `/entity/{entityId}/address/{id}` | `entityId:integer, id:integer` | `204 void` | Delete entity address | | `PATCH` | `/entity/{entityId}/address/{id}` | `entityId:integer, id:integer, body: { addressType?, firstName?, name?, street?, streetNumber?, zip?, city?, county? }` | `200 { address: { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType } }` | Update entity address | | `GET` | `/entity/{entityId}/contact` | `entityId:integer` | `200 { contacts: { id, entityId, contactType, contact }[] }` | List entity contacts | | `POST` | `/entity/{entityId}/contact` | `entityId:integer, body: { contactType, contact }` | `201 { contact: { id, entityId, contactType, contact } }` | Create entity contact | | `DELETE` | `/entity/{entityId}/contact/{id}` | `entityId:integer, id:integer` | `204 void` | Delete entity contact | | `PATCH` | `/entity/{entityId}/contact/{id}` | `entityId:integer, id:integer, body: { contactType?, contact? }` | `200 { contact: { id, entityId, contactType, contact } }` | Update entity contact | | `DELETE` | `/entity/{id}` | `id:integer` | `204 void` | Delete entity | | `GET` | `/entity/{id}` | `id:integer` | `200 { entity: { id, customergroupId, firstName, name, number, createdAt, updatedAt } }` | Get entity | | `PATCH` | `/entity/{id}` | `id:integer, body: { name?, firstName?, number? }` | `200 { entity: { id, customergroupId, firstName, name, number, createdAt, updatedAt } }` | Update entity | | `GET` | `/labeltemplate` | — | `200 { labeltemplates: { id, name, width, height, dpi, type, content, thumb }[] }` | List label templates | | `POST` | `/labeltemplate` | `body: { name, width, height, dpi, type, content }` | `201 { labeltemplate: { id, name, width, height, dpi, type, content, thumb } }` | Create label template | | `DELETE` | `/labeltemplate/{id}` | `id:integer` | `204 void` | Delete label template | | `GET` | `/labeltemplate/{id}` | `id:integer` | `200 { labeltemplate: { id, name, width, height, dpi, type, content, thumb } }` | Get label template by ID | | `PATCH` | `/labeltemplate/{id}` | `id:integer, body: { name?, width?, height?, dpi?, type?, content? }` | `200 { labeltemplate: { id, name, width, height, dpi, type, content, thumb } }` | Update label template (partial) | | `PUT` | `/labeltemplate/{id}` | `id:integer, body: { name?, width?, height?, dpi?, type?, content? }` | `200 { labeltemplate: { id, name, width, height, dpi, type, content, thumb } }` | Update label template | | `GET` | `/ledger` | `query: manifestarticle_id?:integer, sku?:string, transaction_type?:string` | `200 { ledger: { id, manifestarticle_id, transaction_type, amount, transaction_text, hash_version, prev_hash, sku, created_at }[] }` | Query ledger by manifest article ID or SKU | | `POST` | `/ledger` | `body: { manifestarticle_id, transaction_type, amount, transaction_text }` | `201 { ledger: { id, manifestarticle_id, transaction_type, amount, transaction_text, hash_version, prev_hash, sku, created_at } }` | Add ledger entry | | `GET` | `/ledger/manifestarticle/{manifestarticleId}` | `manifestarticleId:integer, query: transaction_type?:string` | `200 { ledger: { id, manifestarticle_id, transaction_type, amount, transaction_text, hash_version, prev_hash, sku, created_at }[] }` | Query ledger by manifest article ID | | `GET` | `/ledger/sku/{sku}` | `sku:string, query: transaction_type?:string` | `200 { ledger: { id, manifestarticle_id, transaction_type, amount, transaction_text, hash_version, prev_hash, sku, created_at }[] }` | Query ledger by article SKU | | `GET` | `/number` | — | `200 { numbers: { id, type, prefix, padding, next }[] }` | List number sequences | | `PATCH` | `/number/{id}` | `id:integer, body: { prefix?, padding?, next? }` | `200 { number: { id, type, prefix, padding, next } }` | Update number sequence | | `GET` | `/order` | — | `200 { orders: { id, number, type, entityId, date, createdAt }[] }` | List orders | | `POST` | `/order` | `body: { number, date, lines: { amount, net, taxrate, sku?: string, name?, pu?, rebate?, comment? }[], entityId? }` | `201 { order: { id, number, type, entityId, date, createdAt, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[] } }` | Create order | | `DELETE` | `/order/{id}` | `id:integer` | `204 void` | Delete order | | `GET` | `/order/{id}` | `id:integer` | `200 { order: { id, number, type, entityId, date, createdAt, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[] } }` | Get order | | `PATCH` | `/order/{id}` | `id:integer, body: { number?, date?, entityId?, lines?: { amount, net, taxrate, sku?: string, name?, pu?, rebate?, comment? }[] }` | `200 { order: { id, number, type, entityId, date, createdAt, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[] } }` | Update order | | `GET` | `/printer` | — | `200 { printers: { id, company_id, address, type, model, serial, sort, desc }[] }` | List printers | | `POST` | `/printer` | `body: { address, type, model?, serial?, sort?, desc? }` | `201 { printer: { id, company_id, address, type, model, serial, sort, desc } }` | Create printer | | `PUT` | `/printer/order` | `body: { printerIds: integer[] }` | `200 { printerIds: integer[] }` | Reorder printers | | `DELETE` | `/printer/{id}` | `id:integer` | `204 void` | Delete printer | | `GET` | `/printer/{id}` | `id:integer` | `200 { printer: { id, company_id, address, type, model, serial, sort, desc } }` | Get printer by ID | | `PATCH` | `/printer/{id}` | `id:integer, body: { address?, type?, model?, serial?, sort?, desc? }` | `200 { printer: { id, company_id, address, type, model, serial, sort, desc } }` | Update printer (partial) | | `PUT` | `/printer/{id}` | `id:integer, body: { address?, type?, model?, serial?, sort?, desc? }` | `200 { printer: { id, company_id, address, type, model, serial, sort, desc } }` | Update printer | | `GET` | `/propertyname` | — | `200 { propertynames: { id, name, sort, exclusive }[] }` | List property names | | `POST` | `/propertyname` | `body: { name, sort?, exclusive? }` | `201 { propertyname: { id, name, sort, exclusive } }` | Create property name | | `PUT` | `/propertyname/order` | `body: { propertynameIds: integer[] }` | `200` | Reorder property names | | `DELETE` | `/propertyname/{id}` | `id:integer` | `200` | Delete property name | | `PATCH` | `/propertyname/{id}` | `id:integer, body: { name?, sort?, exclusive? }` | `200 { propertyname: { id, name, sort, exclusive } }` | Update property name | | `GET` | `/quote` | — | `200 { quotes: { id, number, type, entityId, date, createdAt }[] }` | List quotes | | `POST` | `/quote` | `body: { number, date, lines: { amount, net, taxrate, sku?: string, name?, pu?, rebate?, comment? }[], entityId? }` | `201 { quote: { id, number, type, entityId, date, createdAt, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[] } }` | Create quote | | `DELETE` | `/quote/{id}` | `id:integer` | `204 void` | Delete quote | | `GET` | `/quote/{id}` | `id:integer` | `200 { quote: { id, number, type, entityId, date, createdAt, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[] } }` | Get quote | | `PATCH` | `/quote/{id}` | `id:integer, body: { number?, date?, entityId?, lines?: { amount, net, taxrate, sku?: string, name?, pu?, rebate?, comment? }[] }` | `200 { quote: { id, number, type, entityId, date, createdAt, lines: { id, sku, name, pu, amount, net, rebate, taxrate, comment }[] } }` | Update quote | | `POST` | `/stock/adjust` | `body: { sku?: string, warehouseId?, amount?, text?, lines?: { sku: string, amount, warehouseId?, text? }[] }` | `201 { manifest, lines: object[], ledger: { id, manifestarticle_id, transaction_type, amount, transaction_text, hash_version, prev_hash, sku, created_at }[] }` | Adjust stock manually | | `GET` | `/supplier` | — | `200 { suppliers: { id, name, createdAt, updatedAt }[] }` | List suppliers | | `POST` | `/supplier` | `body: { name: string }` | `201 { supplier: { id, name, createdAt, updatedAt } }` | Create supplier | | `DELETE` | `/supplier/{id}` | `id:integer` | `204 void` | Delete supplier | | `PATCH` | `/supplier/{id}` | `id:integer, body: { name: string }` | `200 { supplier: { id, name, createdAt, updatedAt } }` | Update supplier | | `GET` | `/supplier/{id}/articles` | `id:integer, query: skus?` | `200 { articles: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price, article }[] }` | List supplier articles by SKUs | | `POST` | `/supplier/{id}/articles` | `id:integer, body?: { skus?: string[] }` | `200 { articles: { id, articleId, entityId, supplierName, sku, pu, stock, sort, priceId, price, article }[] }` | Query supplier articles by SKUs (bulk) | | `DELETE` | `/unit` | `query: si:string` | `204 void` | Delete unit | | `GET` | `/unit` | — | `200 { units: { si, basesi, basesifactor, symbol, name }[] }` | List units | | `PUT` | `/unit` | `body: { si, basesi, basesifactor, symbol, name }` | `200 { unit: { si, basesi, basesifactor, symbol, name } }` | Upsert unit | | `GET` | `/warehouse` | — | `200 { warehouses: { id, name, sort }[] }` | List warehouses | | `POST` | `/warehouse` | `body: { name, sort? }` | `201 { warehouse: { id, name, sort } }` | Create warehouse | | `PUT` | `/warehouse/order` | `body: { warehouseIds: integer[] }` | `200 { warehouseIds: integer[] }` | Reorder warehouses | | `DELETE` | `/warehouse/{id}` | `id:integer` | `204 void` | Delete warehouse | | `GET` | `/warehouse/{id}` | `id:integer` | `200 { warehouse: { id, name, sort } }` | Get warehouse by ID | | `PATCH` | `/warehouse/{id}` | `id:integer, body: { name?, sort? }` | `200 { warehouse: { id, name, sort } }` | Update warehouse (partial) | | `PUT` | `/warehouse/{id}` | `id:integer, body: { name?, sort? }` | `200 { warehouse: { id, name, sort } }` | Update warehouse |