{"openapi":"3.0.3","info":{"title":"POS PRO-360 Web POS API (v1)","version":"0.0.1","description":"API for the web back office and POS tills."},"servers":[{"url":"/api/v1","description":"Web POS API v1"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT from POST /auth/login"}},"schemas":{"ApiResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{},"message":{"type":"string"}}},"LoginBody":{"type":"object","required":["login_id","password"],"properties":{"login_id":{"type":"string"},"password":{"type":"string"},"store_code":{"type":"string"}}},"StoreCreateBody":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"phone":{"type":"string"},"timezone":{"type":"string","default":"UTC"},"is_active":{"type":"boolean","default":true}}}}},"tags":[{"name":"Auth","description":"Authentication"},{"name":"POS Devices","description":"POS device registration, validation and login"},{"name":"Apps","description":"Retail apps list"},{"name":"App Settings","description":"Global app settings"},{"name":"Master","description":"Suppliers, categories, brands"},{"name":"Permissions","description":"Menus and role permissions"},{"name":"Users","description":"User list"},{"name":"Stores","description":"Store CRUD"},{"name":"Products","description":"Product CRUD"},{"name":"POS","description":"Point of Sale / Barcode"},{"name":"Settings","description":"Product settings"}],"paths":{"/":{"get":{"tags":[],"summary":"API root","description":"Returns API message and version.","responses":{"200":{"description":"{ message, version }"}}}},"/version":{"get":{"tags":[],"summary":"API version","description":"Returns package version.","responses":{"200":{"description":"{ version }"}}}},"/auth/login":{"post":{"tags":["Auth"],"summary":"Login","description":"Authenticate with login_id and password. Returns access token and refresh token.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginBody"}}}},"responses":{"200":{"description":"Login successful"},"401":{"description":"Invalid credentials"}}}},"/auth/refresh-token":{"post":{"tags":["Auth"],"summary":"Refresh access token","description":"Exchange refresh token for a new access token.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"New access token"},"401":{"description":"Invalid token"}}}},"/auth/logout":{"post":{"tags":["Auth"],"summary":"Logout","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Logout successful"}}}},"/auth/me":{"get":{"tags":["Auth"],"summary":"Current user","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User info"},"401":{"description":"Unauthorized"}}}},"/auth/pos/validate-device":{"get":{"tags":["POS Devices"],"summary":"Validate POS device","description":"Check whether a device_id is active, pending admin approval, banned, or not registered. Used by the POS app in the background on a poll interval; never throws for an unapproved device — only for a malformed request or a server/DB error — so the POS app can distinguish \"not yet approved\" from a transient failure and avoid blocking its UI on the latter. No auth required.","parameters":[{"name":"device_id","in":"query","required":true,"schema":{"type":"string"},"description":"POS device ID (e.g. from device storage)"}],"responses":{"200":{"description":"Body: { success, data: { valid, status, pin_required }, message }. status is 'active' | 'pending' | 'banned' | 'not_found'. When valid and pin_required is true, the POS app must call pos/verify-pin before allowing use."},"400":{"description":"Missing or invalid device_id"},"503":{"description":"Database temporarily unreachable"}}}},"/auth/pos/verify-pin":{"post":{"tags":["POS Devices"],"summary":"Verify POS device security PIN","description":"Verifies a cashier-entered security PIN against the device's stored PIN. Only meaningful when validate-device reported pin_required=true for this device_id; otherwise always valid. No auth required.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["device_id","pin"],"properties":{"device_id":{"type":"string","description":"POS device ID"},"pin":{"type":"string","description":"Cashier-entered PIN"}}}}}},"responses":{"200":{"description":"Body: { success, data: { valid }, message }"},"400":{"description":"Missing device_id or pin"},"404":{"description":"Device not found, inactive or banned"}}}},"/auth/pos/register-device":{"post":{"tags":["POS Devices"],"summary":"Self-register a POS device","description":"Submitted once by the POS app on first setup (cashier enters store_code and device_name; device_id is generated by the app). Creates a pending device row (is_active=false) for an admin to approve via the POS Devices admin page. Idempotent: re-submitting an already-registered device_id returns its current status without changes. No auth required.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["device_id","store_code"],"properties":{"device_id":{"type":"string","description":"POS device ID (generated once by the POS app)"},"device_name":{"type":"string","description":"Cashier-entered display name for this device"},"store_code":{"type":"string","description":"Store code this device belongs to"}}}}}},"responses":{"200":{"description":"Body: { success, data: { status, device_id, store_id, store_code, store_name }, message }. status is 'active' | 'pending'."},"400":{"description":"Missing device_id or store_code"},"403":{"description":"Device is banned"},"404":{"description":"Store code not found"}}}},"/auth/pos-login":{"post":{"tags":["POS Devices"],"summary":"POS device login","description":"Authenticate a POS device with device_id and secret_key. Returns JWT for POS API access. Device must be registered (e.g. via Admin Panel), active and not banned.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["device_id","secret_key"],"properties":{"device_id":{"type":"string","description":"POS device ID"},"secret_key":{"type":"string","description":"Secret key for this device"},"store_code":{"type":"string","description":"Optional store code filter"}}}}}},"responses":{"200":{"description":"Login successful. Body: { success, data: { accessToken, store_id, store_code, store_name } }"},"401":{"description":"Device not found, inactive, banned, or invalid secret key"}}}},"/apps":{"get":{"tags":["Apps"],"summary":"List apps","description":"List retail apps available to the user (id, label, iconId, color, path).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Apps list"},"401":{"description":"Unauthorized"}}}},"/app-settings":{"get":{"tags":["App Settings"],"summary":"Get global app settings","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Global settings or null"},"401":{"description":"Unauthorized"}}}},"/master/suppliers":{"get":{"tags":["Master"],"summary":"List suppliers (store-scoped)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Suppliers (id, name)"},"401":{"description":"Unauthorized"}}}},"/master/categories":{"get":{"tags":["Master"],"summary":"List product categories (store-scoped)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Categories (id, name, parent_id)"},"401":{"description":"Unauthorized"}}}},"/master/brands":{"get":{"tags":["Master"],"summary":"List brands (store-scoped)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Brands (id, name, is_active)"},"401":{"description":"Unauthorized"}}}},"/permissions/menus":{"get":{"tags":["Permissions"],"summary":"List menus","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Active menus"},"401":{"description":"Unauthorized"}}}},"/permissions/me":{"get":{"tags":["Permissions"],"summary":"Current user permissions by role","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Permissions with menu_permission"},"401":{"description":"Unauthorized"}}}},"/users":{"get":{"tags":["Users"],"summary":"List users","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Users (user_id, login_id, username, email)"},"401":{"description":"Unauthorized"}}}},"/stores":{"get":{"tags":["Stores"],"summary":"List stores","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Stores list"},"401":{"description":"Unauthorized"}}},"post":{"tags":["Stores"],"summary":"Create store","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreCreateBody"}}}},"responses":{"201":{"description":"Store created"},"401":{"description":"Unauthorized"}}}},"/pos-devices":{"get":{"tags":["POS Devices"],"summary":"List POS devices","description":"List registered POS devices with store info. Does not return secret_hash.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"POS devices list (id, device_id, store_id, name, is_active, banned, store_name, store_code)"},"401":{"description":"Unauthorized"}}},"post":{"tags":["POS Devices"],"summary":"Add POS device","description":"Register a new POS device. Secret key is hashed and stored; not returned.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["device_id","secret_key","store_id"],"properties":{"device_id":{"type":"string","description":"Unique device identifier"},"secret_key":{"type":"string","description":"Secret key for device login (stored hashed)"},"store_id":{"type":"integer","description":"Store ID"},"name":{"type":"string","description":"Display name (optional)"}}}}}},"responses":{"201":{"description":"POS device created"},"400":{"description":"Validation error or device_id exists"},"401":{"description":"Unauthorized"}}}},"/pos-devices/{id}":{"put":{"tags":["POS Devices"],"summary":"Update POS device","description":"Update name, is_active, banned; optionally provide new secret_key to rotate.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Device primary key"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"is_active":{"type":"boolean"},"banned":{"type":"boolean"},"secret_key":{"type":"string","description":"New secret key (hashed); omit to keep current"}}}}}},"responses":{"200":{"description":"POS device updated"},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"404":{"description":"Device not found"}}},"delete":{"tags":["POS Devices"],"summary":"Remove POS device","description":"Delete a registered POS device.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Device primary key"}],"responses":{"200":{"description":"POS device deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Device not found"}}}},"/pos-cashiers":{"get":{"tags":["POS Devices"],"summary":"List POS cashiers","description":"List cashier accounts (code + name + store) across all stores. Does not return pin_hash.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"POS cashiers list (id, cashier_code, name, store_id, is_active, store_name, store_code)"},"401":{"description":"Unauthorized"}}},"post":{"tags":["POS Devices"],"summary":"Add POS cashier","description":"Create a cashier account. cashier_code must be unique per store (case-insensitive; stored uppercased) — it identifies which cashier is logging in, so the PIN only ever needs to be verified against one row and two cashiers can never collide on PIN alone. PIN is required and hashed; not returned.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cashier_code","name","pin","store_id"],"properties":{"cashier_code":{"type":"string","description":"Short unique code per store (e.g. employee ID) — used to look the cashier up at login"},"name":{"type":"string","description":"Cashier display name"},"pin":{"type":"string","description":"6-digit login PIN (stored hashed)"},"store_id":{"type":"integer","description":"Store ID"}}}}}},"responses":{"201":{"description":"POS cashier created"},"400":{"description":"Validation error, or cashier_code already exists for this store"},"401":{"description":"Unauthorized"}}}},"/pos-cashiers/{id}":{"put":{"tags":["POS Devices"],"summary":"Update POS cashier","description":"Update cashier_code, name, or is_active; optionally provide a new pin to rotate it.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Cashier primary key"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cashier_code":{"type":"string"},"name":{"type":"string"},"is_active":{"type":"boolean"},"pin":{"type":"string","description":"New PIN (hashed); omit to keep current"}}}}}},"responses":{"200":{"description":"POS cashier updated"},"400":{"description":"Validation error, or cashier_code already exists for this store"},"401":{"description":"Unauthorized"},"404":{"description":"Cashier not found"}}},"delete":{"tags":["POS Devices"],"summary":"Remove POS cashier","description":"Delete a cashier account.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Cashier primary key"}],"responses":{"200":{"description":"POS cashier deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Cashier not found"}}}},"/pos/cashier-login":{"post":{"tags":["POS Devices"],"summary":"Identify cashier by cashier_code + PIN","description":"Identifies which cashier is operating the terminal by looking up cashier_code (unique per store) then verifying the PIN against that one cashier — resolved for the store from the caller's device JWT. Requires the POS device to already be authenticated (Authorization: Bearer <device JWT>). Only meaningful when pos-settings reports cashier_login_required=true; the POS app then attaches the returned cashierId/cashierName to every sale it posts until the cashier switches out.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cashierCode","pin"],"properties":{"cashierCode":{"type":"string","description":"Cashier-entered code (case-insensitive)"},"pin":{"type":"string","description":"Cashier-entered PIN"}}}}}},"responses":{"200":{"description":"Body: { success, data: { cashierId, cashierName } | null, message }. data is null when the code/PIN don't match an active cashier at this store."},"400":{"description":"Missing cashierCode or pin"},"401":{"description":"Unauthorized (missing/invalid device JWT)"}}}},"/products/next-code":{"get":{"tags":["Products"],"summary":"Get next product code","description":"Returns the next product code and increments the sequence. Call only when saving a new product. No product id required; uses retail_sequence (module PRODUCT).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Next code allocated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"code":{"type":"string"}}},"message":{"type":"string"}}}}}},"500":{"description":"Sequence not found or server error"}}}},"/products/peek-next-code":{"get":{"tags":["Products"],"summary":"Peek next product code","description":"Returns what the next product code would be without incrementing the sequence. Use for preview (e.g. in form). No product id required.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Preview of next code","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"code":{"type":"string"}}},"message":{"type":"string"}}}}}},"500":{"description":"Sequence not found or server error"}}}},"/products/current-code":{"get":{"tags":["Products"],"summary":"Get current product code","description":"Returns the last allocated product code from the sequence (current value). No product id required.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current (last allocated) code","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"code":{"type":"string"}}},"message":{"type":"string"}}}}}},"500":{"description":"Sequence not found or server error"}}}},"/products/next-variant-code":{"get":{"tags":["Products"],"summary":"Get next variant code","description":"Returns the next variant code and increments the sequence (module VARIANT).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Next variant code"},"500":{"description":"Sequence error"}}}},"/products/peek-next-variant-code":{"get":{"tags":["Products"],"summary":"Peek next variant code","description":"Preview next variant code without incrementing.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Preview next variant code"},"500":{"description":"Sequence error"}}}},"/products/current-variant-code":{"get":{"tags":["Products"],"summary":"Get current variant code","description":"Returns the last allocated variant code.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current variant code"},"500":{"description":"Sequence error"}}}},"/products/import":{"post":{"tags":["Products"],"summary":"Import products","description":"Bulk import products (e.g. CSV upload).","security":[{"bearerAuth":[]}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Import result"},"400":{"description":"Invalid file"},"401":{"description":"Unauthorized"}}}},"/products/export":{"get":{"tags":["Products"],"summary":"Export products","description":"Export products as CSV.","security":[{"bearerAuth":[]}],"parameters":[{"name":"search","in":"query","schema":{"type":"string"}},{"name":"search_type","in":"query","schema":{"type":"string","enum":["all","barcode","code","name"]}}],"responses":{"200":{"description":"CSV file"},"401":{"description":"Unauthorized"}}}},"/products":{"get":{"tags":["Products"],"summary":"List products","description":"Paginated list of products for the store. Supports search by name, code (sku), or barcode.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Page number"},{"name":"limit","in":"query","schema":{"type":"integer","default":10},"description":"Items per page"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search term"},{"name":"search_type","in":"query","schema":{"type":"string","enum":["all","barcode","code","name"]},"description":"Search field"},{"name":"category_id","in":"query","schema":{"type":"integer"},"description":"Filter by category"},{"name":"status","in":"query","schema":{"type":"string"},"description":"Filter by status (e.g. active)"}],"responses":{"200":{"description":"Paginated products (data, total, page, limit, totalPages)"},"401":{"description":"Unauthorized"}}},"post":{"tags":["Products"],"summary":"Create product","description":"Create a new product. Use GET /products/next-code to reserve a code when saving, or provide sku in body.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"sku":{"type":"string"},"product_type":{"type":"string"},"barcode":{"type":"string"},"additional_barcodes":{"type":"string"},"cost_price":{"type":"number"},"sale_price":{"type":"number"},"mrp_price":{"type":"number"},"tax_rate":{"type":"number"},"category_id":{"type":"integer"},"sub_category_id":{"type":"integer"},"brand_id":{"type":"integer"},"supplier_id":{"type":"integer"},"status":{"type":"string"}}}}}},"responses":{"201":{"description":"Product created"},"401":{"description":"Unauthorized"},"409":{"description":"SKU already exists"}}}},"/products/{id}":{"get":{"tags":["Products"],"summary":"Get product by ID","description":"Returns full product detail by numeric id. Do not use literal paths like peek-next-code as id.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Product ID"}],"responses":{"200":{"description":"Product detail"},"400":{"description":"Invalid id"},"404":{"description":"Not found"}}},"put":{"tags":["Products"],"summary":"Update product","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","description":"Partial product fields to update"}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Invalid id"},"404":{"description":"Not found"}}},"delete":{"tags":["Products"],"summary":"Delete product","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"},"400":{"description":"Invalid id"},"404":{"description":"Not found"}}}},"/products/{id}/images":{"post":{"tags":["Products"],"summary":"Upload product image","description":"Add image(s) to a product. Multipart form with file(s).","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Product ID"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Image(s) added"},"400":{"description":"Invalid id"},"401":{"description":"Unauthorized"},"404":{"description":"Product not found"}}}},"/products/{id}/images/{imageId}":{"delete":{"tags":["Products"],"summary":"Delete product image","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Product ID"},{"name":"imageId","in":"path","required":true,"schema":{"type":"string"},"description":"Image ID"}],"responses":{"200":{"description":"Deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"}}}},"/pos/products":{"get":{"tags":["POS"],"summary":"List POS products","description":"List products for POS (store context).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Products list"},"401":{"description":"Unauthorized"}}}},"/pos/products/{id}":{"get":{"tags":["POS"],"summary":"Get POS product by ID","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Product"},"404":{"description":"Not found"}}}},"/pos/products/by-barcode/{barcode}":{"get":{"tags":["POS"],"summary":"Get product by barcode","description":"Lookup product by barcode (barcode or additional_barcodes).","security":[{"bearerAuth":[]}],"parameters":[{"name":"barcode","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product for POS (id, name, sku, barcode, price, stock)"},"404":{"description":"Not found"}}}},"/pos/products/{id}/generate-barcode":{"post":{"tags":["POS"],"summary":"Generate barcode for product","description":"Generate a unique barcode and assign it to the product.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Product ID"}],"responses":{"200":{"description":"Generated barcode (data.barcode, data.barcode_type)"},"400":{"description":"Invalid id"},"404":{"description":"Product not found"}}}},"/pos/barcode/validate":{"post":{"tags":["POS"],"summary":"Validate barcode","description":"Validates barcode format (EAN13, UPC-A, Code128).","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"barcode":{"type":"string"}}}}}},"responses":{"200":{"description":"Validation result (valid, barcode_type, message)"}}}},"/pos/barcode/generate":{"post":{"tags":["POS"],"summary":"Generate barcode","description":"Generate a unique barcode (from retail_pos_settings increment). Optional body: { \"prefix\" } is ignored; numeric 13-digit barcode is returned.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","description":"Optional prefix"}}}}}},"responses":{"200":{"description":"Generated barcode (data.barcode, data.barcode_type)"},"500":{"description":"Generation failed"}}}},"/pos/barcode/image/{barcode}":{"get":{"tags":["POS"],"summary":"Get barcode image","description":"Returns PNG image of the barcode.","security":[{"bearerAuth":[]}],"parameters":[{"name":"barcode","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PNG image","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Invalid barcode"}}}},"/pos/barcode/preview-for-product":{"get":{"tags":["POS"],"summary":"Preview barcode for product","description":"Get barcode preview (e.g. query params for product id / barcode).","security":[{"bearerAuth":[]}],"parameters":[{"name":"product_id","in":"query","schema":{"type":"integer"}},{"name":"barcode","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Preview data"},"401":{"description":"Unauthorized"}}}},"/pos/pos-settings":{"get":{"tags":["POS"],"summary":"Get POS settings","description":"POS-specific settings (store-scoped).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"POS settings"},"401":{"description":"Unauthorized"}}},"post":{"tags":["POS"],"summary":"Update POS settings","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated"},"401":{"description":"Unauthorized"}}}},"/pos/barcode-settings":{"get":{"tags":["POS"],"summary":"Get barcode settings","description":"Barcode type, auto-generate, etc.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Barcode settings"},"401":{"description":"Unauthorized"}}},"post":{"tags":["POS"],"summary":"Update barcode settings","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated"},"401":{"description":"Unauthorized"}}}},"/products/setting/taxes":{"get":{"tags":["Settings"],"summary":"List taxes (paginated)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated taxes"}}},"post":{"tags":["Settings"],"summary":"Create tax","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Tax created"}}}},"/products/setting/taxes/{id}":{"put":{"tags":["Settings"],"summary":"Update tax","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Settings"],"summary":"Delete tax","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"}}}},"/products/setting/brands":{"get":{"tags":["Settings"],"summary":"List brands (paginated)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated brands"}}},"post":{"tags":["Settings"],"summary":"Create brand","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Brand created"}}}},"/products/setting/brands/{id}":{"put":{"tags":["Settings"],"summary":"Update brand","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Settings"],"summary":"Delete brand","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"}}}},"/products/setting/units":{"get":{"tags":["Settings"],"summary":"List units (paginated)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated units"}}},"post":{"tags":["Settings"],"summary":"Create unit","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Unit created"}}}},"/products/setting/units/{id}":{"put":{"tags":["Settings"],"summary":"Update unit","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Settings"],"summary":"Delete unit","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"}}}},"/products/setting/categories":{"get":{"tags":["Settings"],"summary":"List product categories (paginated)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated categories"}}},"post":{"tags":["Settings"],"summary":"Create category","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Category created"}}}},"/products/setting/categories/{id}":{"put":{"tags":["Settings"],"summary":"Update category","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Settings"],"summary":"Delete category","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"}}}},"/products/setting/variant-attributes":{"get":{"tags":["Settings"],"summary":"List variant attributes","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Paginated variant attributes"}}},"post":{"tags":["Settings"],"summary":"Create variant attribute","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created"}}}},"/products/setting/variant-attributes/{id}":{"put":{"tags":["Settings"],"summary":"Update variant attribute","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Settings"],"summary":"Delete variant attribute","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"}}}},"/products/setting/variant-attributes/{attributeId}/values":{"get":{"tags":["Settings"],"summary":"List attribute values","security":[{"bearerAuth":[]}],"parameters":[{"name":"attributeId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Values list"}}},"post":{"tags":["Settings"],"summary":"Create attribute value","security":[{"bearerAuth":[]}],"parameters":[{"name":"attributeId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"201":{"description":"Created"}}}},"/products/setting/variant-attributes/{attributeId}/values/{id}":{"put":{"tags":["Settings"],"summary":"Update attribute value","security":[{"bearerAuth":[]}],"parameters":[{"name":"attributeId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Settings"],"summary":"Delete attribute value","security":[{"bearerAuth":[]}],"parameters":[{"name":"attributeId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"}}}},"/products/setting/sequences":{"get":{"tags":["Settings"],"summary":"List sequences","description":"List all retail_sequence rows (e.g. PRODUCT, STORE, VARIANT) for code generation.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Array of { module, number, prefix, suffix, column_length, is_append_prefix, is_append_suffix }"},"500":{"description":"Server error"}}},"post":{"tags":["Settings"],"summary":"Create sequence","description":"Create a new sequence for a module.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"module":{"type":"string"},"number":{"type":"integer"},"prefix":{"type":"string"},"suffix":{"type":"string"},"column_length":{"type":"integer"},"is_append_prefix":{"type":"boolean"},"is_append_suffix":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Sequence created"},"401":{"description":"Unauthorized"}}}},"/products/setting/sequences/{module}":{"put":{"tags":["Settings"],"summary":"Update sequence","description":"Update sequence for a module (e.g. PRODUCT, STORE, VARIANT). Body: number, prefix, suffix, column_length, is_append_prefix, is_append_suffix.","security":[{"bearerAuth":[]}],"parameters":[{"name":"module","in":"path","required":true,"schema":{"type":"string"},"description":"Module name (e.g. PRODUCT, STORE, VARIANT)"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"number":{"type":"integer"},"prefix":{"type":"string"},"suffix":{"type":"string"},"column_length":{"type":"integer"},"is_append_prefix":{"type":"boolean"},"is_append_suffix":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated sequence"},"404":{"description":"Sequence not found"},"500":{"description":"Server error"}}}},"/products/setting/payment-settings":{"get":{"tags":["Settings"],"summary":"List payment settings","description":"Payment types from `retail_payment_settings` (store-scoped rows + global `store_id` null).","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"active_only","in":"query","description":"If true, return only rows where is_active is true (recommended for POS).","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Paginated payment settings"},"401":{"description":"Unauthorized"}}},"post":{"tags":["Settings"],"summary":"Create payment setting","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"201":{"description":"Created"},"401":{"description":"Unauthorized"}}}},"/products/setting/payment-settings/{id}":{"put":{"tags":["Settings"],"summary":"Update payment setting","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated"},"401":{"description":"Unauthorized"}}},"delete":{"tags":["Settings"],"summary":"Delete payment setting","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"},"401":{"description":"Unauthorized"}}}}}}