{"openapi":"3.1.0","info":{"title":"SupplySynk API","version":"1.0.0","description":"Inventory, orders, purchasing and stock operations for a SupplySynk organization. The organization is always the one the API key belongs to. Errors use a single envelope `{ error: { code, message, details?, request_id } }`; a path id that isn't a UUID is 404 not_found. Cost prices and cost-derived values (stock value at cost, margins, purchase-order amounts) are visible to API keys and to members with the staff role or above; for viewers (dashboard sessions or OAuth agents acting for a viewer) those fields are omitted from the response, not set to null."},"servers":[{"url":"/api/v1"}],"security":[{"bearerAuth":[]},{"basicAuth":[]}],"tags":[{"name":"Products"},{"name":"Inventory"},{"name":"Reports"},{"name":"Orders"},{"name":"Counter"},{"name":"Purchase orders"},{"name":"Transfers"},{"name":"Stock counts"},{"name":"Webhooks"},{"name":"Square"},{"name":"Online store"},{"name":"Notifications"},{"name":"Storefront API","description":"Publishable keys for the public Storefront API (`/api/storefront/v1`: store, categories, products, cart, checkout, order status), which websites such as bzlabs.io sites call with `Authorization: Bearer pk_live_…`.","externalDocs":{"description":"Storefront API (OpenAPI)","url":"/api/storefront/v1/openapi.json"}},{"name":"Marketing"},{"name":"GST documents"},{"name":"Tax"},{"name":"AI"},{"name":"Customers"},{"name":"Suppliers"},{"name":"Locations"},{"name":"Categories"}],"paths":{"/products":{"get":{"operationId":"listProducts","tags":["Products"],"summary":"List products","description":"`costPrice` is omitted for viewers.\n\nRequires scope `read:products`.","x-required-scope":"read:products","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":200}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","draft","archived"]}},{"name":"categoryId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"parentId","in":"query","required":false,"description":"Only the variants of this product","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"preferredSupplierId","in":"query","required":false,"description":"Only products whose preferred supplier is this supplier","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"ids","in":"query","required":false,"description":"Only these product IDs (array, or comma-separated in a query string)","schema":{"anyOf":[{"maxItems":100,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"type":"string"}]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createProduct","tags":["Products"],"summary":"Create a product","description":"Requires scope `write:products`.","x-required-scope":"write:products","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":300},"sku":{"type":"string","minLength":1,"maxLength":100},"barcode":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"description":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}]},"shortDescription":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"categoryId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"preferredSupplierId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"costPrice":{"type":"number","minimum":0,"maximum":1000000000},"sellingPrice":{"type":"number","minimum":0,"maximum":1000000000},"compareAtPrice":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000},{"type":"null"}]},"taxRate":{"anyOf":[{"type":"number","minimum":0,"maximum":100},{"type":"null"}],"description":"The product's own tax rate in percent (India: its GST rate, one of the slabs; US: overrides the business's sales tax rate). null = the business default"},"taxExempt":{"type":"boolean","description":"No tax on this product (US exempt goods; India exempt supplies)"},"hsnCode":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"description":"India: HSN or SAC code, 4, 6 or 8 digits"},"mrp":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000},{"type":"null"}],"description":"India: Maximum Retail Price (tax included). The selling price can't be above it"},"unit":{"anyOf":[{"type":"string","enum":["pcs","kg","g","L","ml","m","dozen","pair","set"]},{"type":"null"}],"description":"Unit it's sold in: pcs, kg, g, L, ml, m, dozen, pair or set"},"countryOfOrigin":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"description":"India store: country of origin, e.g. India"},"manufacturerRole":{"anyOf":[{"type":"string","enum":["manufacturer","packer","importer"]},{"type":"null"}],"description":"Whose name and address are given: manufacturer, packer or importer"},"manufacturerName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"India store: name of the manufacturer, packer or importer"},"manufacturerAddress":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"description":"India store: their full address"},"netQuantity":{"anyOf":[{"type":"number","exclusiveMinimum":0,"maximum":100000000},{"type":"null"}],"description":"India store: net quantity in the pack, e.g. 500 (with netQuantityUnit g)"},"netQuantityUnit":{"anyOf":[{"type":"string","enum":["pcs","kg","g","L","ml","m","dozen","pair","set"]},{"type":"null"}],"description":"Unit of the net quantity: pcs, kg, g, L, ml, m, dozen, pair or set"},"bestBefore":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"Optional best-before or expiry text, e.g. Best before 12 months from packing"},"legalNote":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"description":"Any other declaration the store must show, e.g. size or an FSSAI licence number"},"trackInventory":{"type":"boolean"},"allowBackorder":{"type":"boolean"},"lowStockThreshold":{"type":"integer","minimum":0,"maximum":1000000000},"reorderPoint":{"type":"integer","minimum":0,"maximum":1000000000},"reorderQuantity":{"type":"integer","minimum":0,"maximum":1000000000},"weight":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000},{"type":"null"}]},"weightUnit":{"type":"string","enum":["kg","g","lb","oz"]},"tags":{"maxItems":50,"type":"array","items":{"type":"string","maxLength":50}},"status":{"type":"string","enum":["active","draft","archived"]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"trackLots":{"type":"boolean","description":"Track lots/batches with expiry dates (FEFO picking)"},"options":{"minItems":1,"maxItems":3,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"values":{"minItems":1,"maxItems":100,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}}},"required":["name","values"],"additionalProperties":false},"description":"Variant options, e.g. [{\"name\":\"Size\",\"values\":[\"S\",\"M\",\"L\"]}]"},"variants":{"minItems":1,"maxItems":250,"type":"array","items":{"type":"object","properties":{"options":{"type":"object","propertyNames":{"type":"string","minLength":1,"maxLength":50},"additionalProperties":{"type":"string","minLength":1,"maxLength":100},"description":"Option values, e.g. {\"Size\":\"M\"}"},"sku":{"type":"string","minLength":1,"maxLength":100},"barcode":{"type":"string","maxLength":100},"sellingPrice":{"description":"Defaults to the parent's price","type":"number","minimum":0,"maximum":1000000000},"costPrice":{"type":"number","minimum":0,"maximum":1000000000}},"required":["options"],"additionalProperties":false}}},"required":["name","sellingPrice"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/products/lookup":{"get":{"operationId":"lookupProduct","tags":["Products"],"summary":"Find a product by barcode or SKU","description":"Barcode first, then SKU (case-insensitive). Includes stock at each location. `costPrice` is omitted for viewers.\n\nRequires scope `read:products`.","x-required-scope":"read:products","parameters":[{"name":"code","in":"query","required":true,"description":"Scanned barcode, or a SKU","schema":{"type":"string","minLength":1,"maxLength":100}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/products/{id}":{"get":{"operationId":"getProduct","tags":["Products"],"summary":"Get a product","description":"Includes stock per location and, for a variant family, its variants. `costPrice` is omitted for viewers.\n\nRequires scope `read:products`.","x-required-scope":"read:products","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateProduct","tags":["Products"],"summary":"Update a product","description":"Requires scope `write:products`.","x-required-scope":"write:products","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":300},"sku":{"type":"string","minLength":1,"maxLength":100},"barcode":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"description":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}]},"shortDescription":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"categoryId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"preferredSupplierId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"costPrice":{"type":"number","minimum":0,"maximum":1000000000},"sellingPrice":{"type":"number","minimum":0,"maximum":1000000000},"compareAtPrice":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000},{"type":"null"}]},"taxRate":{"anyOf":[{"type":"number","minimum":0,"maximum":100},{"type":"null"}],"description":"The product's own tax rate in percent (India: its GST rate, one of the slabs; US: overrides the business's sales tax rate). null = the business default"},"taxExempt":{"type":"boolean","description":"No tax on this product (US exempt goods; India exempt supplies)"},"hsnCode":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"description":"India: HSN or SAC code, 4, 6 or 8 digits"},"mrp":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000},{"type":"null"}],"description":"India: Maximum Retail Price (tax included). The selling price can't be above it"},"unit":{"anyOf":[{"type":"string","enum":["pcs","kg","g","L","ml","m","dozen","pair","set"]},{"type":"null"}],"description":"Unit it's sold in: pcs, kg, g, L, ml, m, dozen, pair or set"},"countryOfOrigin":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"description":"India store: country of origin, e.g. India"},"manufacturerRole":{"anyOf":[{"type":"string","enum":["manufacturer","packer","importer"]},{"type":"null"}],"description":"Whose name and address are given: manufacturer, packer or importer"},"manufacturerName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"India store: name of the manufacturer, packer or importer"},"manufacturerAddress":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"description":"India store: their full address"},"netQuantity":{"anyOf":[{"type":"number","exclusiveMinimum":0,"maximum":100000000},{"type":"null"}],"description":"India store: net quantity in the pack, e.g. 500 (with netQuantityUnit g)"},"netQuantityUnit":{"anyOf":[{"type":"string","enum":["pcs","kg","g","L","ml","m","dozen","pair","set"]},{"type":"null"}],"description":"Unit of the net quantity: pcs, kg, g, L, ml, m, dozen, pair or set"},"bestBefore":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"Optional best-before or expiry text, e.g. Best before 12 months from packing"},"legalNote":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"description":"Any other declaration the store must show, e.g. size or an FSSAI licence number"},"trackInventory":{"type":"boolean"},"allowBackorder":{"type":"boolean"},"lowStockThreshold":{"type":"integer","minimum":0,"maximum":1000000000},"reorderPoint":{"type":"integer","minimum":0,"maximum":1000000000},"reorderQuantity":{"type":"integer","minimum":0,"maximum":1000000000},"weight":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000},{"type":"null"}]},"weightUnit":{"type":"string","enum":["kg","g","lb","oz"]},"tags":{"maxItems":50,"type":"array","items":{"type":"string","maxLength":50}},"status":{"type":"string","enum":["active","draft","archived"]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"trackLots":{"type":"boolean","description":"Track lots/batches with expiry dates (FEFO picking)"}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteProduct","tags":["Products"],"summary":"Delete a product","description":"Returns 409 if the product is referenced by orders or purchase orders; archive it instead.\n\nRequires scope `write:products`.","x-required-scope":"write:products","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/products/{id}/images/generate":{"post":{"operationId":"generateProductImage","tags":["Products"],"summary":"Generate an AI image for a product","description":"Makes a studio shot, lifestyle scene, cleaned-up background or custom image (from the product's main photo when it has one, else from its name and description) and adds it to the product's photos with `generated: true`. Usually takes 10-30 seconds, sometimes up to a minute or two when the AI service is busy; gives up with 503 `generation_failed` after about 90 seconds. Uses one of the month's AI images (see `GET /ai/image-allowance`); 429 `image_allowance_used` when none are left, 422 `generation_failed` when the AI declines. Response: `{ image, images, allowance }`.\n\nRequires scope `write:products`.","x-required-scope":"write:products","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"style":{"default":"studio","type":"string","enum":["studio","lifestyle","clean_background","custom"]},"imageId":{"type":"string","maxLength":64},"usePhoto":{"default":true,"type":"boolean"},"instructions":{"type":"string","maxLength":500}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/products/{id}/describe":{"post":{"operationId":"describeProductPhoto","tags":["Products"],"summary":"Draft listing copy from a product photo","description":"Reads the product's main photo (or `imageId`) and drafts name, description, short description, tags, category (one of yours, or null) and alt text. Nothing is saved: apply what you want with `PATCH /products/{id}`.\n\nRequires scope `write:products`.","x-required-scope":"write:products","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"imageId":{"type":"string","maxLength":64},"name":{"type":"string","maxLength":200},"notes":{"type":"string","maxLength":500}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/products/describe-photo":{"post":{"operationId":"describeNewProductPhoto","tags":["Products"],"summary":"Draft a new product from a photo","description":"Upload a photo (multipart, up to 10 MB; downscale to about 2048 px first) and get a draft name, description, tags, category and alt text for a new product. Nothing is saved.\n\nRequires scope `write:products`.","x-required-scope":"write:products","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The photo (JPEG, PNG, WebP or AVIF)"},"name":{"type":"string","description":"Optional: what you call the product"},"notes":{"type":"string","description":"Optional: anything the AI should know"}}}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/ai/image-allowance":{"get":{"operationId":"getImageAllowance","tags":["Products"],"summary":"AI images left this month","description":"`{ used, limit, resetsAt }`. Free plans include 5 AI images a month, Pro 100.\n\nRequires scope `read:products`.","x-required-scope":"read:products","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/products/{id}/variants":{"post":{"operationId":"addProductVariant","tags":["Products"],"summary":"Add a variant","description":"Adds a variant (own SKU, price and stock) to a variant family; option values must match the family's options.\n\nRequires scope `write:products`.","x-required-scope":"write:products","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"options":{"type":"object","propertyNames":{"type":"string","minLength":1,"maxLength":50},"additionalProperties":{"type":"string","minLength":1,"maxLength":100},"description":"Option values, e.g. {\"Size\":\"M\"}"},"sku":{"type":"string","minLength":1,"maxLength":100},"barcode":{"type":"string","maxLength":100},"sellingPrice":{"description":"Defaults to the parent's price","type":"number","minimum":0,"maximum":1000000000},"costPrice":{"type":"number","minimum":0,"maximum":1000000000}},"required":["options"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/inventory":{"get":{"operationId":"listInventoryLevels","tags":["Inventory"],"summary":"List stock levels","description":"On-hand, reserved, available and incoming quantities per product and location.\n\nRequires scope `read:inventory`.","x-required-scope":"read:inventory","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"productId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"locationId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"belowReorderPoint","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["0","1","true","false"]}]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/inventory/adjustments":{"post":{"operationId":"adjustInventory","tags":["Inventory"],"summary":"Adjust stock","description":"Provide exactly one of `quantity` (set on-hand) or `adjustment` (delta). The `reason` is recorded in the stock ledger and shown in the product's stock history. `binLocation` (shelf or bin) can be set together with `quantity`.\n\nRequires scope `write:inventory`.","x-required-scope":"write:inventory","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"description":"Set on-hand to exactly this","type":"integer","minimum":0,"maximum":100000000},"adjustment":{"description":"Add (+) or remove (-) units","type":"integer","minimum":-100000000,"maximum":100000000},"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Why the stock changed (shown in the ledger and the product's stock history)"},"binLocation":{"description":"Shelf or bin at this location, e.g. \"A3\". Only with quantity (setting stock)","type":"string","minLength":1,"maxLength":100},"lotNumber":{"description":"Lot-tracked products: lot receiving added units","type":"string","minLength":1,"maxLength":100},"expiryDate":{"description":"Lot-tracked products: expiry of that lot (YYYY-MM-DD)","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"lots":{"description":"Lot-tracked products: remove from these lots instead of first-expiry-first-out","maxItems":100,"type":"array","items":{"type":"object","properties":{"lotNumber":{"type":"string","minLength":1,"maxLength":100},"quantity":{"type":"integer","minimum":1,"maximum":9007199254740991}},"required":["lotNumber","quantity"]}}},"required":["productId","locationId","reason"]}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/inventory/movements":{"get":{"operationId":"listMovements","tags":["Inventory"],"summary":"List stock movements (ledger)","description":"Newest first. Filter by `productId` for one product's stock history. Each movement has the change, before/after quantities, location, type, the document that caused it and the reason (`notes`).\n\nRequires scope `read:inventory`.","x-required-scope":"read:inventory","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"productId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"locationId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"referenceType","in":"query","required":false,"schema":{"type":"string","maxLength":50}},{"name":"referenceId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/inventory/lots":{"get":{"operationId":"listInventoryLots","tags":["Inventory"],"summary":"List lots","description":"Lots/batches with expiry, soonest expiry first. Filter with expiringWithinDays for an expiry report.\n\nRequires scope `read:inventory`.","x-required-scope":"read:inventory","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"productId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"locationId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"expiringWithinDays","in":"query","required":false,"description":"Only lots expiring within N days (incl. expired)","schema":{"type":"integer","minimum":0,"maximum":3650}},{"name":"includeEmpty","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["0","1","true","false"]}]}},{"name":"search","in":"query","required":false,"description":"Match SKU, product name or lot number","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/inventory/lots/trace":{"get":{"operationId":"traceLot","tags":["Inventory"],"summary":"Trace a lot","description":"Every movement that touched a lot (receipts, shipments, transfers, adjustments) for recalls.\n\nRequires scope `read:inventory`.","x-required-scope":"read:inventory","parameters":[{"name":"productId","in":"query","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"lotNumber","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":100}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/attention":{"get":{"operationId":"getAttentionItems","tags":["Reports"],"summary":"What needs attention","description":"Live counts of what needs doing: products at or below their reorder point, out of stock, orders to fulfil, and Square sales or refunds that didn't sync in the last 7 days. Items only appear if the caller may read them (`read:inventory` / `read:orders`). Response: `{ data: AttentionItem[], total }`.\n\nRequires scope `read:inventory`.","x-required-scope":"read:inventory","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/insights":{"get":{"operationId":"getInsights","tags":["Reports"],"summary":"Sales and stock insights","description":"Sales (net of returns, ex tax) by day or week in the business's time zone, best sellers, categories, stock value, dead stock and slow movers. Costs, stock value and margins are omitted for viewers (staff and up, and API keys, see them); `costsVisible` says which. Amounts are in the business currency (`period.currency`); `period.country` is the business's country (US or IN).\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"days","in":"query","required":false,"description":"Period: the last 7, 30, 90 or 365 days","schema":{"default":30,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},{"name":"deadDays","in":"query","required":false,"description":"No sale for this many days = dead stock","schema":{"default":90,"type":"integer","minimum":30,"maximum":365}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/insights/weekly-summary":{"get":{"operationId":"getWeeklySummary","tags":["Reports"],"summary":"Weekly summary","description":"One week (Monday to Sunday in the business's time zone; `weekStart` is the Monday, default last week): sales vs the week before, top 5 products, sales by channel, low stock and reorder suggestions, dead stock, marketing results when marketing is on, merchandising suggestions and 2-3 AI-written suggestions (`aiSuggestions.source` is `ai`, or `rules` when the AI wasn't used; AI sentences with a figure that isn't in the data are dropped). The same content the Monday email has. Built and kept the first time it's read or sent. No costs or margins.\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"weekStart","in":"query","required":false,"description":"Monday the week starts on (YYYY-MM-DD, business time zone); default last week","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/insights/weekly-summaries":{"get":{"operationId":"listWeeklySummaries","tags":["Reports"],"summary":"Past weekly summaries","description":"Newest first, with each week's revenue, orders, change and when the email was sent (`sentAt`).\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/insights/merch-suggestions":{"get":{"operationId":"listMerchSuggestions","tags":["Reports"],"summary":"Merchandising suggestions","description":"Rule-based ideas for this week, best first, at most 5 of each kind: `reorder` (a top seller that's low), `overstock` (lots of stock for its sales: run a promotion), `dead_stock` (bundle or discount), `new_arrival` (feature it) and `improve_listing` (no photo or description). Each has a plain `reason` with its figures and the `actions` it offers. `definitions` explains each rule. Selling-price figures only, no costs.\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"kind","in":"query","required":false,"description":"Only one kind of suggestion","schema":{"type":"string","enum":["reorder","overstock","dead_stock","new_arrival","improve_listing"]}},{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":25}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/insights/merch-suggestions/reorder-draft":{"post":{"operationId":"createProductReorderDraft","tags":["Reports"],"summary":"Draft a reorder for one product","description":"A draft purchase order from the product's preferred supplier into `locationId` (default: the default location). Quantity: given, else the reorder quantity, else enough for about 4 weeks of sales. 400 when the product has no preferred supplier; 409 when it's already on a draft PO from that supplier. Drafts don't change stock.\n\nRequires scope `write:purchase_orders`.","x-required-scope":"write:purchase_orders","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"Product to reorder (a variant, or a product without variants)"},"locationId":{"description":"Location to receive into; default is the business's default location","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"description":"Default: the product's reorder quantity, else enough for about 4 weeks of sales","type":"integer","minimum":1,"maximum":1000000}},"required":["productId"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/insights/merch-suggestions/post-draft":{"post":{"operationId":"createProductPostDraft","tags":["Reports"],"summary":"Draft a social post about a product","description":"Creates a marketing post draft for the product (a variant's family) with its main photo and a buy link per network to your store, through the marketing post service: the same as `POST /marketing/posts`, which needs `write:marketing` (staff and up). Nothing is published. Returns `{ id, url }`; open the post to write or generate the caption.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"Product to post about (its buy link is added)"},"caption":{"description":"Caption to start from; leave out to write it in the post editor","type":"string","maxLength":5000}},"required":["productId"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/inventory/reorder-suggestions":{"get":{"operationId":"getReorderSuggestions","tags":["Inventory"],"summary":"Reorder suggestions","description":"Products at or below their reorder point. Response: `{ data: ReorderSuggestion[] }`. `unitCost` is omitted for viewers.\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"locationId","in":"query","required":false,"description":"Limit to one location; default is all locations combined","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/inventory/reorder-suggestions/drafts":{"post":{"operationId":"createReorderDrafts","tags":["Inventory"],"summary":"Create draft POs from reorder suggestions","description":"One draft purchase order per preferred supplier.\n\nRequires scope `write:purchase_orders`.","x-required-scope":"write:purchase_orders","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"Location to receive the replenishment into"},"supplierId":{"description":"Only this supplier's suggestions; default: one draft PO per supplier","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"required":["locationId"]}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders":{"get":{"operationId":"listOrders","tags":["Orders"],"summary":"List orders","description":"Requires scope `read:orders`.","x-required-scope":"read:orders","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","confirmed","partially_fulfilled","fulfilled","cancelled"]}},{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"channel","in":"query","required":false,"description":"Only orders from this channel: online (the online store), counter (counter billing), square, manual or api","schema":{"type":"string","maxLength":50}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createOrder","tags":["Orders"],"summary":"Create an order","description":"Reserves stock immediately unless `confirm` is false. Tax is worked out from the business's tax settings (GST or US sales tax; none until set up) unless a `taxAmount` is given on any line or the order, in which case the amounts given are used as they are. The response has the breakup: `taxBreakup`, each item's `taxes`, `taxRegime`, `taxInclusive`, `placeOfSupply` and `roundOff`. India: a price above the product's MRP is refused (`above_mrp`).\n\nRequires scope `write:orders`.\n\nSupports the `Idempotency-Key` header.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"description":"Fulfilment location; defaults to the default location","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"customerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"customerName":{"type":"string","maxLength":200},"customerEmail":{"type":"string","maxLength":320,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"channel":{"default":"api","type":"string","maxLength":50},"channelOrderId":{"type":"string","maxLength":200},"billingAddress":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"shippingAddress":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"items":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"unitPrice":{"description":"Defaults to the product's selling price","type":"number","minimum":0,"maximum":1000000000},"discountAmount":{"default":0,"description":"Discount on this line (not per unit)","type":"number","minimum":0,"maximum":1000000000},"taxAmount":{"description":"Tax on this line (not per unit). Give tax amounts only to override the tax engine: when any line or the order has a taxAmount, the amounts given are used as they are (0 when missing) and nothing is calculated","type":"number","minimum":0,"maximum":1000000000}},"required":["productId","quantity"]}},"discountAmount":{"default":0,"description":"Order-level discount, on top of line discounts. The order's discountAmount is the sum of both","type":"number","minimum":0,"maximum":1000000000},"taxAmount":{"description":"Order-level tax, on top of line taxes. The order's taxAmount is the sum of both. Omit it (and line taxAmounts) to have tax calculated from the business's tax settings","type":"number","minimum":0,"maximum":1000000000},"buyerGstin":{"description":"India: the customer's GSTIN (a business purchase); checked","type":"string","maxLength":20},"placeOfSupply":{"description":"India: state (name or GST code) where the supply ends. Defaults to the selling location's state (in-store, pickup); another state charges IGST","type":"string","maxLength":60},"shippingAmount":{"default":0,"type":"number","minimum":0,"maximum":1000000000},"notes":{"type":"string","maxLength":5000},"confirm":{"default":true,"description":"Reserve stock immediately (status confirmed)","type":"boolean"}},"required":["items"]}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}":{"get":{"operationId":"getOrder","tags":["Orders"],"summary":"Get an order with its items","description":"Requires scope `read:orders`.","x-required-scope":"read:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateOrder","tags":["Orders"],"summary":"Update order details","description":"Non-stock fields only; use the confirm/fulfill/cancel actions to change status.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customerName":{"type":"string","maxLength":200},"customerEmail":{"type":"string","maxLength":320,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"billingAddress":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"shippingAddress":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"paymentStatus":{"type":"string","enum":["pending","paid","partially_paid","refunded","failed"]},"shippingMethod":{"type":"string","maxLength":200},"trackingNumber":{"type":"string","maxLength":200},"trackingUrl":{"type":"string","maxLength":2000,"format":"uri"},"notes":{"type":"string","maxLength":5000},"internalNotes":{"type":"string","maxLength":5000},"tags":{"maxItems":50,"type":"array","items":{"type":"string","maxLength":50}}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/confirm":{"post":{"operationId":"confirmOrder","tags":["Orders"],"summary":"Confirm an order","description":"Reserves stock for a pending order.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/fulfill":{"post":{"operationId":"fulfillOrder","tags":["Orders"],"summary":"Fulfill an order","description":"Ships all outstanding lines, or only the given quantities.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Ship only these quantities; omit to ship everything outstanding","maxItems":500,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":9007199254740991}},"required":["productId","quantity"]}},"trackingNumber":{"type":"string","maxLength":200},"trackingUrl":{"type":"string","maxLength":2000,"format":"uri"},"shippingMethod":{"type":"string","maxLength":200}}}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/cancel":{"post":{"operationId":"cancelOrder","tags":["Orders"],"summary":"Cancel an order","description":"Releases reservations. Shipped orders can't be cancelled.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":2000}}}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/returns":{"post":{"operationId":"returnOrderItems","tags":["Orders"],"summary":"Record a customer return","description":"Returns shipped units; restocked units go back on hand with a `return` ledger movement.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"restock":{"default":true,"description":"Put the units back into sellable stock (false = write off)","type":"boolean"},"lotNumber":{"description":"Lot-tracked products: lot to restock into","type":"string","minLength":1,"maxLength":100},"expiryDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["productId","quantity"]}},"locationId":{"description":"Location receiving restocked units; defaults to the order's location","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"reason":{"type":"string","maxLength":500}},"required":["items"]}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/online":{"get":{"operationId":"getOnlineOrderDetails","tags":["Orders"],"summary":"Online store details of an order","description":"For orders placed in the online store (`channel: \"online\"`): how the shopper pays (`provider`), the UPI reference they entered, pickup location, phone, when the stock hold expires, and payments recorded. 404 for other orders.\n\nRequires scope `read:orders`.","x-required-scope":"read:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/mark-paid":{"post":{"operationId":"markOrderPaid","tags":["Orders"],"summary":"Mark an online order paid","description":"For pay at pickup and UPI orders (providers that can't confirm payments themselves): records the payment, sets `paymentStatus: paid` and emails the shopper. Idempotent. Refused for cancelled or expired orders and for providers that confirm automatically.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reference":{"description":"Optional note of the payment (e.g. the UPI reference you checked, or 'cash')","type":"string","maxLength":100}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/ready-for-pickup":{"post":{"operationId":"markOrderReadyForPickup","tags":["Orders"],"summary":"Mark an online order ready for pickup","description":"Sets `fulfillmentStatus: ready_for_pickup`, emails the shopper (once) and stops the stock hold from expiring. Idempotent.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/picked-up":{"post":{"operationId":"markOrderPickedUp","tags":["Orders"],"summary":"Mark an online order picked up","description":"Fulfils the order (stock leaves through the order service). An unpaid order needs `markPaid: true` (payment taken at the counter).\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"markPaid":{"description":"Also record the payment taken at the counter (pay at pickup)","type":"boolean"},"reference":{"type":"string","maxLength":100}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/refund":{"post":{"operationId":"refundOnlineOrder","tags":["Orders"],"summary":"Refund an online order's payment","description":"Refunds the order's payment in full through its provider (Stripe, PayPal, Razorpay or Square), on the shop's own account, and records it (`paymentStatus: refunded`). Owners and admins signed in to SupplySynk only; API keys and AI agents are refused. Doesn't change stock: cancel the order to put the items back on sale. Pay at pickup and UPI payments are refunded outside SupplySynk.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"description":"Why, for your records and (PayPal) the shopper","type":"string","maxLength":200}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/counter":{"get":{"operationId":"getCounterSetup","tags":["Counter"],"summary":"Counter billing setup","description":"Currency, whether tax is set up and prices include it, whether sales get a GST invoice (`issuesGstInvoices`), the ways to pay (`paymentMethods`: cash, card, and upi when the shop's UPI ID is set in Settings → Payments) and the counter sales not finished yet (`open`, newest 100, with `openTotal`): waiting for a UPI payment (`paymentStatus: pending`) or paid but not handed over (`paid`; finish with `/paid` or cancel). `waiting` lists the UPI ones.\n\nRequires scope `read:orders`.","x-required-scope":"read:orders","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/counter/sales":{"post":{"operationId":"createCounterSale","tags":["Counter"],"summary":"Sell at the counter","description":"Creates the order (`channel: \"counter\"`) at each product's selling price with tax from the tax engine, records the payment (cash, card, or UPI to the shop's own UPI ID; SupplySynk never handles the money), hands the goods over (stock leaves the location through the stock engine) and, for GST-registered businesses in India, issues the tax invoice or bill of supply. Not enough stock: nothing is created. UPI with `payment.paid: false` stops after creating the order (stock reserved) and returns `upi.uri` (show it as a QR); confirm with `POST /counter/sales/{id}/paid` or cancel with `POST /counter/sales/{id}/cancel`. With an `Idempotency-Key`, a retry or double submit returns the same sale as it is now (never a second sale), even when the first request failed after the sale was saved. A phone number finds (needs read:customers) or saves the customer; `customerId` needs read:customers. India B2B: `customer.gstin` with name and billing address. Returns the sale with `invoice.publicUrl` and a `whatsappUrl`.\n\nRequires scope `write:orders`.\n\nSupports the `Idempotency-Key` header.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"The shop (location) selling; stock leaves from here"},"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":100000}},"required":["productId","quantity"],"additionalProperties":false},"description":"Lines at each product's selling price"},"discountAmount":{"default":0,"description":"Discount on the whole bill (spread over the lines before tax)","type":"number","minimum":0,"maximum":1000000000},"customer":{"type":"object","properties":{"customerId":{"description":"An existing customer (needs read:customers)","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"name":{"description":"Name on the bill (a walk-in customer)","type":"string","maxLength":200},"phone":{"description":"Mobile number: finds the customer with this number (needs read:customers), or saves a new one (needs write:customers); used for the WhatsApp link","type":"string","maxLength":50},"gstin":{"description":"India: the buyer's GSTIN for a business (B2B) bill; then name and billingAddress are required","type":"string","maxLength":20},"billingAddress":{"description":"{ line1, line2, city, region (state), postalCode }","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"payment":{"type":"object","properties":{"method":{"type":"string","enum":["cash","card","upi"]},"paid":{"default":true,"description":"false (UPI only): create the sale waiting for payment and get the UPI QR; confirm with mark paid","type":"boolean"},"reference":{"description":"UPI: the 12-digit reference (UTR) you checked; card: the slip or approval number","type":"string","maxLength":100}},"required":["method"],"additionalProperties":false},"notes":{"type":"string","maxLength":2000}},"required":["locationId","items","payment"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/counter/sales/{id}":{"get":{"operationId":"getCounterSale","tags":["Counter"],"summary":"Get a counter sale","description":"The order, payment, UPI link (while waiting), GST invoice, `whatsappUrl` and the shop details for a printed receipt. 404 for orders that aren't counter sales.\n\nRequires scope `read:orders`.","x-required-scope":"read:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/counter/sales/{id}/paid":{"post":{"operationId":"markCounterSalePaid","tags":["Counter"],"summary":"Confirm a counter sale's UPI payment","description":"Staff checked the payment arrived in their UPI app: records it (optionally with the 12-digit UTR), hands the goods over and issues the GST invoice. Also finishes a paid sale whose goods weren't handed over. Safe to repeat; refused for cancelled sales.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reference":{"description":"UPI: the 12-digit reference (UTR) you checked","type":"string","maxLength":100}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/counter/sales/{id}/cancel":{"post":{"operationId":"cancelCounterSale","tags":["Counter"],"summary":"Cancel a counter sale","description":"For a sale not handed over (waiting for UPI, or paid but stuck): the stock goes back on sale and a recorded payment is marked refunded (give the money back). Handed-over sales are returned from the order. Safe to repeat.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/purchase-orders":{"get":{"operationId":"listPurchaseOrders","tags":["Purchase orders"],"summary":"List purchase orders","description":"`subtotal`, `taxAmount`, `shippingAmount` and `totalAmount` are omitted for viewers.\n\nRequires scope `read:purchase_orders`.","x-required-scope":"read:purchase_orders","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","ordered","partially_received","received","cancelled"]}},{"name":"supplierId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createPurchaseOrder","tags":["Purchase orders"],"summary":"Create a purchase order","description":"Without a `taxAmount`, input tax is worked out for GST-registered businesses in India (each product's GST rate on its cost; CGST+SGST from a supplier in the same state, IGST from another) and stored per line (`taxes`); otherwise it's the amount given, or none.\n\nRequires scope `write:purchase_orders`.\n\nSupports the `Idempotency-Key` header.","x-required-scope":"write:purchase_orders","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"supplierId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$","description":"Location the goods will be received into"},"items":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"unitCost":{"description":"Defaults to the product's cost price","type":"number","minimum":0,"maximum":1000000000}},"required":["productId","quantity"]}},"expectedAt":{"type":"string","format":"date-time"},"currency":{"description":"Defaults to the business currency","type":"string","minLength":3,"maxLength":3},"taxAmount":{"description":"Tax on the whole PO, used as given. Omit it to have input tax worked out (India, GST-registered businesses: each product's GST rate on its cost; otherwise none)","type":"number","minimum":0,"maximum":1000000000},"shippingAmount":{"default":0,"type":"number","minimum":0,"maximum":1000000000},"notes":{"type":"string","maxLength":5000},"submit":{"default":false,"description":"Mark as ordered immediately (counts stock as incoming)","type":"boolean"}},"required":["supplierId","locationId","items"]}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/purchase-orders/{id}":{"get":{"operationId":"getPurchaseOrder","tags":["Purchase orders"],"summary":"Get a purchase order with its items","description":"For viewers the header amounts (`subtotal`, `taxAmount`, `shippingAmount`, `totalAmount`) and each item's `unitCost` and `totalCost` are omitted.\n\nRequires scope `read:purchase_orders`.","x-required-scope":"read:purchase_orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/purchase-orders/{id}/submit":{"post":{"operationId":"submitPurchaseOrder","tags":["Purchase orders"],"summary":"Submit a purchase order","description":"draft → ordered; quantities count as incoming stock.\n\nRequires scope `write:purchase_orders`.","x-required-scope":"write:purchase_orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/purchase-orders/{id}/receive":{"post":{"operationId":"receivePurchaseOrder","tags":["Purchase orders"],"summary":"Receive goods","description":"Receives everything outstanding, or only the given quantities.\n\nRequires scope `write:purchase_orders`.","x-required-scope":"write:purchase_orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Quantities received now (a product may repeat with different lots); omit to receive everything outstanding","maxItems":500,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"lotNumber":{"description":"Lot/batch number (lot-tracked products)","type":"string","minLength":1,"maxLength":100},"expiryDate":{"description":"Lot expiry date, YYYY-MM-DD","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["productId","quantity"]}},"notes":{"type":"string","maxLength":2000}}}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/purchase-orders/{id}/cancel":{"post":{"operationId":"cancelPurchaseOrder","tags":["Purchase orders"],"summary":"Cancel a purchase order","description":"Only draft or ordered POs with nothing received.\n\nRequires scope `write:purchase_orders`.","x-required-scope":"write:purchase_orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/transfers":{"get":{"operationId":"listTransfers","tags":["Transfers"],"summary":"List stock transfers","description":"Requires scope `read:inventory`.","x-required-scope":"read:inventory","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","in_transit","received","cancelled"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createTransfer","tags":["Transfers"],"summary":"Create a stock transfer","description":"Requires scope `write:inventory`.\n\nSupports the `Idempotency-Key` header.","x-required-scope":"write:inventory","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fromLocationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"toLocationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"items":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":1000000}},"required":["productId","quantity"]}},"notes":{"type":"string","maxLength":5000},"ship":{"default":false,"description":"Ship immediately (removes stock from the source)","type":"boolean"}},"required":["fromLocationId","toLocationId","items"]}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/transfers/{id}":{"get":{"operationId":"getTransfer","tags":["Transfers"],"summary":"Get a transfer with its items","description":"Requires scope `read:inventory`.","x-required-scope":"read:inventory","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/transfers/{id}/ship":{"post":{"operationId":"shipTransfer","tags":["Transfers"],"summary":"Ship a transfer","description":"draft → in_transit; removes stock from the source location.\n\nRequires scope `write:inventory`.","x-required-scope":"write:inventory","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/transfers/{id}/receive":{"post":{"operationId":"receiveTransfer","tags":["Transfers"],"summary":"Receive a transfer","description":"in_transit → received; adds stock at the destination.\n\nRequires scope `write:inventory`.","x-required-scope":"write:inventory","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/transfers/{id}/cancel":{"post":{"operationId":"cancelTransfer","tags":["Transfers"],"summary":"Cancel a transfer","description":"In-transit stock returns to the source location.\n\nRequires scope `write:inventory`.","x-required-scope":"write:inventory","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/stock-counts":{"get":{"operationId":"listStockCounts","tags":["Stock counts"],"summary":"List stock counts","description":"Requires scope `read:inventory`.","x-required-scope":"read:inventory","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","completed","cancelled"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createStockCount","tags":["Stock counts"],"summary":"Open a stock count","description":"Snapshots expected quantities at the location.\n\nRequires scope `write:inventory`.","x-required-scope":"write:inventory","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"productIds":{"description":"Products to count; omit to count everything stocked at the location","maxItems":5000,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"notes":{"type":"string","maxLength":5000}},"required":["locationId"]}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/stock-counts/{id}":{"get":{"operationId":"getStockCount","tags":["Stock counts"],"summary":"Get a stock count with its lines","description":"Requires scope `read:inventory`.","x-required-scope":"read:inventory","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/stock-counts/{id}/lines":{"post":{"operationId":"recordStockCount","tags":["Stock counts"],"summary":"Record counted quantities","description":"Requires scope `write:inventory`.","x-required-scope":"write:inventory","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"minItems":1,"maxItems":5000,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"countedQuantity":{"type":"integer","minimum":0,"maximum":100000000}},"required":["productId","countedQuantity"]}}},"required":["lines"]}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/stock-counts/{id}/complete":{"post":{"operationId":"completeStockCount","tags":["Stock counts"],"summary":"Complete a stock count","description":"Posts variances to stock as ledger movements.\n\nRequires scope `write:inventory`.","x-required-scope":"write:inventory","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/stock-counts/{id}/cancel":{"post":{"operationId":"cancelStockCount","tags":["Stock counts"],"summary":"Cancel a stock count","description":"Requires scope `write:inventory`.","x-required-scope":"write:inventory","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/webhooks/events":{"get":{"operationId":"listWebhookEventTypes","tags":["Webhooks"],"summary":"List event types","description":"Every event type an endpoint can subscribe to, with what triggers it.\n\nRequires scope `manage:webhooks`.","x-required-scope":"manage:webhooks","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/webhooks":{"get":{"operationId":"listWebhooks","tags":["Webhooks"],"summary":"List webhook endpoints","description":"Response: `{ data: Webhook[] }`. Secrets are never listed.\n\nRequires scope `manage:webhooks`.","x-required-scope":"manage:webhooks","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createWebhook","tags":["Webhooks"],"summary":"Add a webhook endpoint","description":"Returns the endpoint with its signing `secret`, shown only once. Deliveries are signed `SupplySynk-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>`. Up to 25 endpoints per business.\n\nRequires scope `manage:webhooks`.","x-required-scope":"manage:webhooks","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"url":{"type":"string","maxLength":2000,"description":"https URL on the public internet"},"events":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","enum":["product.created","product.updated","product.deleted","inventory.updated","inventory.low_stock","inventory.out_of_stock","order.created","order.updated","order.fulfilled","order.cancelled","order.returned","order.paid","order.ready_for_pickup","customer.created","customer.updated","supplier.created","supplier.updated","purchase_order.created","purchase_order.received","stock_transfer.shipped","stock_transfer.received","stock_count.completed","contact.created","contact.consent_changed","store_page.published","store_page.unpublished","ai_insight.generated"]},"description":"Event types to receive; see GET /webhooks/events"}},"required":["name","url","events"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/webhooks/{id}":{"get":{"operationId":"getWebhook","tags":["Webhooks"],"summary":"Get a webhook endpoint","description":"Requires scope `manage:webhooks`.","x-required-scope":"manage:webhooks","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateWebhook","tags":["Webhooks"],"summary":"Update a webhook endpoint","description":"Change name, URL or events, pause or resume, or `rotateSecret: true` (the new secret is returned once).\n\nRequires scope `manage:webhooks`.","x-required-scope":"manage:webhooks","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"url":{"type":"string","maxLength":2000,"description":"https URL on the public internet"},"events":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","enum":["product.created","product.updated","product.deleted","inventory.updated","inventory.low_stock","inventory.out_of_stock","order.created","order.updated","order.fulfilled","order.cancelled","order.returned","order.paid","order.ready_for_pickup","customer.created","customer.updated","supplier.created","supplier.updated","purchase_order.created","purchase_order.received","stock_transfer.shipped","stock_transfer.received","stock_count.completed","contact.created","contact.consent_changed","store_page.published","store_page.unpublished","ai_insight.generated"]}},"status":{"type":"string","enum":["active","paused"],"description":"paused stops deliveries; active resumes (and clears the failure streak)"},"rotateSecret":{"type":"boolean","const":true,"description":"Issue a new signing secret (returned once)"}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteWebhook","tags":["Webhooks"],"summary":"Delete a webhook endpoint","description":"Requires scope `manage:webhooks`.","x-required-scope":"manage:webhooks","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/webhooks/{id}/deliveries":{"get":{"operationId":"listWebhookDeliveries","tags":["Webhooks"],"summary":"List deliveries","description":"Recent deliveries to the endpoint, newest first: event, status (pending, succeeded, dead), attempts, last HTTP status and error.\n\nRequires scope `manage:webhooks`.","x-required-scope":"manage:webhooks","parameters":[{"$ref":"#/components/parameters/Id"},{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","succeeded","dead"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/square":{"get":{"operationId":"getSquareStatus","tags":["Square"],"summary":"Square connection status","description":"Whether Square is connected, the seller, and which SupplySynk location each Square location sells from. `connection` is null when not connected.\n\nRequires scope `read:locations`.","x-required-scope":"read:locations","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"disconnectSquare","tags":["Square"],"summary":"Disconnect Square","description":"Revokes Square's tokens. Catalog links, the sync log and sales history are kept for a reconnect.\n\nRequires scope `manage:integrations`.","x-required-scope":"manage:integrations","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/square/locations":{"patch":{"operationId":"updateSquareLocations","tags":["Square"],"summary":"Map Square locations","description":"Which SupplySynk location each Square location's sales come out of. `null` unlinks; sales there then wait in the sync log.\n\nRequires scope `manage:integrations`.","x-required-scope":"manage:integrations","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"links":{"type":"object","propertyNames":{"type":"string","minLength":1,"maxLength":100},"additionalProperties":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]}}},"required":["links"]}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/square/catalog":{"get":{"operationId":"getSquareCatalogReview","tags":["Square"],"summary":"Review the Square catalog link","description":"Linked products, suggested matches (same SKU, else same barcode/UPC; only unambiguous ones), Square-only variations and SupplySynk-only products.\n\nRequires scope `write:products`.","x-required-scope":"write:products","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"applySquareCatalog","tags":["Square"],"summary":"Link, import or create catalog items","description":"Link products to Square variations, unlink, import Square-only variations as products, or create SupplySynk-only products in Square. `startingCounts` decides which side's stock wins for newly linked products. Per-item problems are returned in `errors`.\n\nRequires scope `write:products`.","x-required-scope":"write:products","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"link":{"default":[],"maxItems":5000,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"variationId":{"type":"string","minLength":1,"maxLength":100}},"required":["productId","variationId"]}},"unlink":{"default":[],"maxItems":5000,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"importFromSquare":{"default":[],"description":"Square variation ids to create as SupplySynk products","maxItems":2000,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"createInSquare":{"default":[],"description":"SupplySynk products to create in Square","maxItems":1000,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"startingCounts":{"default":"none","description":"For newly linked products: copy Square's counts into SupplySynk, push SupplySynk's to Square, or leave both","type":"string","enum":["square","supplysynk","none"]}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/square/events":{"get":{"operationId":"listSquareEvents","tags":["Square"],"summary":"Square sync log","description":"Every Square event (sales, refunds) and stock push, newest first, with what happened. Failed entries can be retried.\n\nRequires scope `read:orders`.","x-required-scope":"read:orders","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["processed","skipped","failed","received"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/square/events/{id}/retry":{"post":{"operationId":"retrySquareEvent","tags":["Square"],"summary":"Retry a Square event","description":"Processes a failed event again (e.g. after linking its location). Already-recorded sales are never recorded twice.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/square/stock-sync":{"post":{"operationId":"syncSquareStock","tags":["Square"],"summary":"Push all counts to Square","description":"Sends the on-hand count of every linked product at every mapped location to Square. Changes are also pushed automatically after each stock change, and in full daily.\n\nRequires scope `write:inventory`.","x-required-scope":"write:inventory","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/square/sales-summary":{"get":{"operationId":"getSquareSalesSummary","tags":["Square"],"summary":"Daily Square takings by payment type","description":"Per day (business time zone): payments, sales, tips, refunds, Square fees and net, split by card / cash / wallet / other. From Square's payments, so it includes unitemized sales.\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"from","in":"query","required":false,"description":"First day (business time zone); default 6 days before `to`","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":false,"description":"Last day; default today","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/square/sales-summary/refresh":{"post":{"operationId":"refreshSquarePayments","tags":["Square"],"summary":"Re-read Square payments","description":"Fetches Square's payments for the range (e.g. from before connecting) into the summary. Doesn't create orders or change stock.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"description":"First day (business time zone); default 6 days before `to`","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"to":{"description":"Last day; default today","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/settings":{"get":{"operationId":"getStorefrontSettings","tags":["Online store"],"summary":"Online store settings","description":"Whether the store is published, where it opens (`businessAddressUrl`, the business address; `customDomainUrls`, verified custom domains; `storePath`, the `/s/<slug>` path on any SupplySynk host, used for previews) and a short checklist (product photos, store hours, contact details; India: grievance contact and returns policy). India: `sellerInfo` (grievance officer, returns policy).\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"put":{"operationId":"updateStorefrontSettings","tags":["Online store"],"summary":"Publish the online store; new-order emails","description":"`{ \"published\": true }` opens the store to everyone; `false` hides it again (members can still preview). Shoppers see active products with prices, photos and In stock / Only N left / Out of stock; never costs, suppliers or stock counts. `{ \"orderAlerts\": { \"enabled\": true, \"extraEmail\": \"orders@shop.com\" } }` sets the \"New online order\" emails to owners and admins (on by default) and one extra address. India: `{ \"sellerInfo\": { \"grievanceName\": \"…\", \"grievanceEmail\": \"…\", \"grievancePhone\": \"…\", \"returnsPolicy\": \"…\" } }` sets the seller details the store shows (null clears a field). Send any of them. Members need the owner or admin role.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"published":{"description":"true opens the store to everyone; false hides it again","type":"boolean"},"orderAlerts":{"description":"\"New online order\" emails (SHOP-5)","type":"object","properties":{"enabled":{"description":"Email owners and admins about each new online order","type":"boolean"},"extraEmail":{"description":"One more address that gets the emails (null removes it)","anyOf":[{"type":"string","maxLength":254,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]}},"additionalProperties":false},"sellerInfo":{"description":"Seller details an Indian online store shows: grievance officer and returns policy (null clears a field)","type":"object","properties":{"grievanceName":{"description":"India: name of the grievance officer","anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"grievanceDesignation":{"description":"India: their designation, e.g. Owner","anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"grievanceEmail":{"description":"India: grievance officer's email","anyOf":[{"type":"string","maxLength":254,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"grievancePhone":{"description":"India: grievance officer's phone","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"returnsPolicy":{"description":"Returns and refunds policy shown on the store's /returns page (India)","anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]}},"additionalProperties":false}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/recommendations":{"get":{"operationId":"listStorePlacements","tags":["Online store"],"summary":"Pinned and excluded products","description":"The store's recommendation blocks (\"Popular now\", \"New arrivals\", \"You may also like\") pick in-stock products from sales, products bought together and categories. `pinned` products always show first (in the order they were pinned, up to `maxPins`); `excluded` products never show.\n\nRequires scope `read:products`.","x-required-scope":"read:products","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/recommendations/{productId}":{"get":{"operationId":"getStorePlacement","tags":["Online store"],"summary":"A product's placement","description":"`mode`: `pin`, `exclude` or `none`.\n\nRequires scope `read:products`.","x-required-scope":"read:products","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"put":{"operationId":"setStorePlacement","tags":["Online store"],"summary":"Pin or exclude a product","description":"`{ \"mode\": \"pin\" }` shows it first in the store's recommendations, `exclude` keeps it out, `none` goes back to automatic. A variant is placed through its family. 409 `too_many_pins` past the limit. Managers and up.\n\nRequires scope `write:products`.","x-required-scope":"write:products","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["pin","exclude","none"],"description":"pin: always show first in the store's recommendations; exclude: never show; none: back to automatic"}},"required":["mode"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages":{"get":{"operationId":"listStorePages","tags":["Online store"],"summary":"List store pages","description":"Home, About and landing pages with `status` (`draft` or `published`), `hasUnpublishedChanges`, `path` on the store (`/`, `/about`, `/p/<slug>`), `draftSource` (`person`, `ai`, or `template` when the AI fell back to rules) and `version`.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createStorePage","tags":["Online store"],"summary":"Create a draft page","description":"`kind`: `home` or `about` (one each) or `landing` with a `slug` (its address is `/p/<slug>`). `sections` is an ordered list of typed sections: `hero`, `rich_text` (paragraphs, `- ` lists, `**bold**`, `*italic*`, `[links](/path)`; no HTML), `product_grid` (`source`: `manual` product ids, a `category`, `popular` or `new_arrivals`), `category_links`, `image_text`, `faq`, `testimonial` (only people signed in to SupplySynk add or change these; API keys and AI apps get 403 `testimonial_by_person_only`), `newsletter`. Links are store paths or https, mailto: and tel: URLs. Images are `{ source: \"product\", productId, imageId, alt }` (a real product photo, never an AI one) or a page image from `POST /storefront/pages/images`; every image needs `alt`. 409 `page_exists` when that page already exists. Managers and up.\n\nRequires scope `write:products`.","x-required-scope":"write:products","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["home","about","landing"]},"slug":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"title":{"type":"string","minLength":1,"maxLength":120},"seoTitle":{"anyOf":[{"type":"string","maxLength":70},{"type":"null"}]},"seoDescription":{"anyOf":[{"type":"string","maxLength":160},{"type":"null"}]},"sections":{"maxItems":30,"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"hero"},"heading":{"type":"string","minLength":1,"maxLength":120},"subheading":{"type":"string","maxLength":300},"image":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","const":"product"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"imageId":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[\\w-]+$"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","productId","imageId","alt"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","const":"page"},"keyPrefix":{"type":"string","maxLength":200,"pattern":"^[0-9a-f-]{36}\\/pages\\/[\\w-]{6,40}$"},"url":{"type":"string","maxLength":1000,"format":"uri"},"mediumUrl":{"type":"string","maxLength":1000,"format":"uri"},"thumbUrl":{"type":"string","maxLength":1000,"format":"uri"},"width":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"height":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"generated":{"type":"boolean"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","keyPrefix","url","mediumUrl","thumbUrl","generated","alt"],"additionalProperties":false}]},"cta":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":40},"href":{"type":"string","minLength":1,"maxLength":500}},"required":["label","href"],"additionalProperties":false}},"required":["id","type","heading"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"rich_text"},"heading":{"type":"string","maxLength":120},"body":{"type":"string","minLength":1,"maxLength":5000}},"required":["id","type","body"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"product_grid"},"heading":{"type":"string","maxLength":120},"source":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"manual"},"productIds":{"minItems":1,"maxItems":24,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}},"required":["mode","productIds"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"category"},"categoryId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"required":["mode","categoryId"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"popular"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"new_arrivals"}},"required":["mode"],"additionalProperties":false}]},"limit":{"default":8,"type":"integer","minimum":1,"maximum":24}},"required":["id","type","source"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"category_links"},"heading":{"type":"string","maxLength":120},"categoryIds":{"minItems":1,"maxItems":12,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}},"required":["id","type","categoryIds"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"image_text"},"heading":{"type":"string","maxLength":120},"body":{"type":"string","minLength":1,"maxLength":2000},"image":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","const":"product"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"imageId":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[\\w-]+$"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","productId","imageId","alt"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","const":"page"},"keyPrefix":{"type":"string","maxLength":200,"pattern":"^[0-9a-f-]{36}\\/pages\\/[\\w-]{6,40}$"},"url":{"type":"string","maxLength":1000,"format":"uri"},"mediumUrl":{"type":"string","maxLength":1000,"format":"uri"},"thumbUrl":{"type":"string","maxLength":1000,"format":"uri"},"width":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"height":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"generated":{"type":"boolean"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","keyPrefix","url","mediumUrl","thumbUrl","generated","alt"],"additionalProperties":false}]},"imageSide":{"default":"left","type":"string","enum":["left","right"]},"cta":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":40},"href":{"type":"string","minLength":1,"maxLength":500}},"required":["label","href"],"additionalProperties":false}},"required":["id","type","body","image"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"faq"},"heading":{"type":"string","maxLength":120},"items":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"question":{"type":"string","minLength":1,"maxLength":200},"answer":{"type":"string","minLength":1,"maxLength":1500}},"required":["question","answer"],"additionalProperties":false}}},"required":["id","type","items"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"testimonial"},"quote":{"type":"string","minLength":1,"maxLength":600},"author":{"type":"string","minLength":1,"maxLength":80},"detail":{"type":"string","maxLength":80}},"required":["id","type","quote","author"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"newsletter"},"heading":{"type":"string","maxLength":120},"text":{"type":"string","maxLength":300}},"required":["id","type"],"additionalProperties":false}]}}},"required":["kind","title"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages/ai-draft":{"post":{"operationId":"draftStorePageWithAi","tags":["Online store"],"summary":"Draft a page with AI","description":"AI writes the words from the business profile; rules pick the products (catalog search and categories for a landing page `brief`, best sellers and new arrivals for the home page) and the store's own photos. The AI may only choose among those products; sentences with prices, discounts, stock, reviews or figures that aren't the owner's are removed. Never customer quotes. Falls back to a rule-based draft (`source: \"template\"`, with a `note`) when the AI is unavailable. Pass `id` and `version` to redraft an existing page (its customer quotes are kept). Always a draft: publishing is a person's job.\n\nRequires scope `write:products`.","x-required-scope":"write:products","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["home","about","landing"]},"brief":{"type":"string","maxLength":300},"slug":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"version":{"type":"integer","minimum":1,"maximum":9007199254740991}},"required":["kind"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages/preview":{"post":{"operationId":"previewStorePage","tags":["Online store"],"summary":"Preview sections","description":"`{ sections }` resolved as the store would show them (products with prices and availability, categories, photos). Nothing is saved.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"sections":{"maxItems":30,"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"hero"},"heading":{"type":"string","minLength":1,"maxLength":120},"subheading":{"type":"string","maxLength":300},"image":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","const":"product"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"imageId":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[\\w-]+$"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","productId","imageId","alt"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","const":"page"},"keyPrefix":{"type":"string","maxLength":200,"pattern":"^[0-9a-f-]{36}\\/pages\\/[\\w-]{6,40}$"},"url":{"type":"string","maxLength":1000,"format":"uri"},"mediumUrl":{"type":"string","maxLength":1000,"format":"uri"},"thumbUrl":{"type":"string","maxLength":1000,"format":"uri"},"width":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"height":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"generated":{"type":"boolean"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","keyPrefix","url","mediumUrl","thumbUrl","generated","alt"],"additionalProperties":false}]},"cta":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":40},"href":{"type":"string","minLength":1,"maxLength":500}},"required":["label","href"],"additionalProperties":false}},"required":["id","type","heading"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"rich_text"},"heading":{"type":"string","maxLength":120},"body":{"type":"string","minLength":1,"maxLength":5000}},"required":["id","type","body"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"product_grid"},"heading":{"type":"string","maxLength":120},"source":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"manual"},"productIds":{"minItems":1,"maxItems":24,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}},"required":["mode","productIds"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"category"},"categoryId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"required":["mode","categoryId"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"popular"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"new_arrivals"}},"required":["mode"],"additionalProperties":false}]},"limit":{"default":8,"type":"integer","minimum":1,"maximum":24}},"required":["id","type","source"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"category_links"},"heading":{"type":"string","maxLength":120},"categoryIds":{"minItems":1,"maxItems":12,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}},"required":["id","type","categoryIds"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"image_text"},"heading":{"type":"string","maxLength":120},"body":{"type":"string","minLength":1,"maxLength":2000},"image":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","const":"product"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"imageId":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[\\w-]+$"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","productId","imageId","alt"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","const":"page"},"keyPrefix":{"type":"string","maxLength":200,"pattern":"^[0-9a-f-]{36}\\/pages\\/[\\w-]{6,40}$"},"url":{"type":"string","maxLength":1000,"format":"uri"},"mediumUrl":{"type":"string","maxLength":1000,"format":"uri"},"thumbUrl":{"type":"string","maxLength":1000,"format":"uri"},"width":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"height":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"generated":{"type":"boolean"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","keyPrefix","url","mediumUrl","thumbUrl","generated","alt"],"additionalProperties":false}]},"imageSide":{"default":"left","type":"string","enum":["left","right"]},"cta":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":40},"href":{"type":"string","minLength":1,"maxLength":500}},"required":["label","href"],"additionalProperties":false}},"required":["id","type","body","image"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"faq"},"heading":{"type":"string","maxLength":120},"items":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"question":{"type":"string","minLength":1,"maxLength":200},"answer":{"type":"string","minLength":1,"maxLength":1500}},"required":["question","answer"],"additionalProperties":false}}},"required":["id","type","items"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"testimonial"},"quote":{"type":"string","minLength":1,"maxLength":600},"author":{"type":"string","minLength":1,"maxLength":80},"detail":{"type":"string","maxLength":80}},"required":["id","type","quote","author"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"newsletter"},"heading":{"type":"string","maxLength":120},"text":{"type":"string","maxLength":300}},"required":["id","type"],"additionalProperties":false}]}}},"required":["sections"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages/images":{"post":{"operationId":"uploadStorePageImage","tags":["Online store"],"summary":"Upload a page photo","description":"Multipart, up to 10 MB. Returns an image (`source: \"page\"`, `generated: false`) to put in a banner or image-and-text section.\n\nRequires scope `write:products`.","x-required-scope":"write:products","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The photo (JPEG, PNG, WebP or AVIF)"},"alt":{"type":"string","description":"What the photo shows (required)"}}}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages/images/generate":{"post":{"operationId":"generateStorePageImage","tags":["Online store"],"summary":"Generate a decorative image","description":"An AI-made background or banner image (`generated: true`, labelled \"AI-generated\"). The prompt forbids showing products for sale, text or logos: product sections always use the store's real photos. Counts against the monthly AI image allowance; 10-90 seconds.\n\nRequires scope `write:products`.","x-required-scope":"write:products","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","minLength":3,"maxLength":400,"description":"What the decorative image should show, e.g. 'a sunny cricket ground at the start of the season'"},"alt":{"type":"string","maxLength":250}},"required":["description"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages/{id}":{"get":{"operationId":"getStorePage","tags":["Online store"],"summary":"A store page","description":"`draft` (being edited) and `published` (what the store shows, null while not published), SEO title and description, and `version`.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateStorePage","tags":["Online store"],"summary":"Change a page's draft","description":"Send the `version` you read; 409 `version_conflict` if someone changed it since. The store keeps showing the published copy until the page is published again. A landing page's `slug` changes only while unpublished. Leaving out `sections` keeps them exactly as stored. A stored section that no longer passes the checks is listed in `invalidSections` on `GET`: fix or remove it (it's never dropped for you); publishing is 409 `invalid_stored_section` until then.\n\nRequires scope `write:products`.","x-required-scope":"write:products","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The page's `version` when you read it; a newer one on the server is 409 version_conflict"},"title":{"type":"string","minLength":1,"maxLength":120},"slug":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"seoTitle":{"anyOf":[{"type":"string","maxLength":70},{"type":"null"}]},"seoDescription":{"anyOf":[{"type":"string","maxLength":160},{"type":"null"}]},"sections":{"maxItems":30,"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"hero"},"heading":{"type":"string","minLength":1,"maxLength":120},"subheading":{"type":"string","maxLength":300},"image":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","const":"product"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"imageId":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[\\w-]+$"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","productId","imageId","alt"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","const":"page"},"keyPrefix":{"type":"string","maxLength":200,"pattern":"^[0-9a-f-]{36}\\/pages\\/[\\w-]{6,40}$"},"url":{"type":"string","maxLength":1000,"format":"uri"},"mediumUrl":{"type":"string","maxLength":1000,"format":"uri"},"thumbUrl":{"type":"string","maxLength":1000,"format":"uri"},"width":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"height":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"generated":{"type":"boolean"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","keyPrefix","url","mediumUrl","thumbUrl","generated","alt"],"additionalProperties":false}]},"cta":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":40},"href":{"type":"string","minLength":1,"maxLength":500}},"required":["label","href"],"additionalProperties":false}},"required":["id","type","heading"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"rich_text"},"heading":{"type":"string","maxLength":120},"body":{"type":"string","minLength":1,"maxLength":5000}},"required":["id","type","body"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"product_grid"},"heading":{"type":"string","maxLength":120},"source":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"manual"},"productIds":{"minItems":1,"maxItems":24,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}},"required":["mode","productIds"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"category"},"categoryId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"required":["mode","categoryId"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"popular"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"new_arrivals"}},"required":["mode"],"additionalProperties":false}]},"limit":{"default":8,"type":"integer","minimum":1,"maximum":24}},"required":["id","type","source"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"category_links"},"heading":{"type":"string","maxLength":120},"categoryIds":{"minItems":1,"maxItems":12,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}},"required":["id","type","categoryIds"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"image_text"},"heading":{"type":"string","maxLength":120},"body":{"type":"string","minLength":1,"maxLength":2000},"image":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","const":"product"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"imageId":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[\\w-]+$"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","productId","imageId","alt"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","const":"page"},"keyPrefix":{"type":"string","maxLength":200,"pattern":"^[0-9a-f-]{36}\\/pages\\/[\\w-]{6,40}$"},"url":{"type":"string","maxLength":1000,"format":"uri"},"mediumUrl":{"type":"string","maxLength":1000,"format":"uri"},"thumbUrl":{"type":"string","maxLength":1000,"format":"uri"},"width":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"height":{"type":"integer","exclusiveMinimum":0,"maximum":10000},"generated":{"type":"boolean"},"alt":{"type":"string","minLength":1,"maxLength":250,"description":"What the image shows, for people who can't see it"}},"required":["source","keyPrefix","url","mediumUrl","thumbUrl","generated","alt"],"additionalProperties":false}]},"imageSide":{"default":"left","type":"string","enum":["left","right"]},"cta":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":40},"href":{"type":"string","minLength":1,"maxLength":500}},"required":["label","href"],"additionalProperties":false}},"required":["id","type","body","image"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"faq"},"heading":{"type":"string","maxLength":120},"items":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"question":{"type":"string","minLength":1,"maxLength":200},"answer":{"type":"string","minLength":1,"maxLength":1500}},"required":["question","answer"],"additionalProperties":false}}},"required":["id","type","items"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"testimonial"},"quote":{"type":"string","minLength":1,"maxLength":600},"author":{"type":"string","minLength":1,"maxLength":80},"detail":{"type":"string","maxLength":80}},"required":["id","type","quote","author"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"},"type":{"type":"string","const":"newsletter"},"heading":{"type":"string","maxLength":120},"text":{"type":"string","maxLength":300}},"required":["id","type"],"additionalProperties":false}]}}},"required":["version"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteStorePage","tags":["Online store"],"summary":"Delete a page","description":"Only while it isn't published (409 otherwise: unpublish it first).\n\nRequires scope `write:products`.","x-required-scope":"write:products","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages/{id}/publish":{"post":{"operationId":"publishStorePage","tags":["Online store"],"summary":"Publish a page","description":"Copies the draft to the store (`/`, `/about` or `/p/<slug>`), the sitemap and the Storefront API. Sends `store_page.published`. Owners and admins; for AI apps it waits for approval.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The page's `version` when you read it; a newer one on the server is 409 version_conflict"}},"required":["version"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages/{id}/unpublish":{"post":{"operationId":"unpublishStorePage","tags":["Online store"],"summary":"Unpublish a page","description":"Takes the page off the store (an unpublished home page means the store's standard home shows again). The draft stays. Sends `store_page.unpublished`. Owners and admins.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The page's `version` when you read it; a newer one on the server is 409 version_conflict"}},"required":["version"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/pages/{id}/revert":{"post":{"operationId":"revertStorePage","tags":["Online store"],"summary":"Discard draft changes","description":"The draft goes back to what the store shows. 409 if the page was never published.\n\nRequires scope `write:products`.","x-required-scope":"write:products","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"The page's `version` when you read it; a newer one on the server is 409 version_conflict"}},"required":["version"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/notifications/preferences":{"get":{"operationId":"getNotificationPreferences","tags":["Notifications"],"summary":"Your email choices","description":"The signed-in member's choices for this business: `weeklySummary.enabled` (owners and admins get it unless they turn it off; managers can opt in; staff and viewers can't). Members only, not API keys.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateNotificationPreferences","tags":["Notifications"],"summary":"Change your email choices","description":"`{ \"weeklySummary\": false }` stops the weekly summary email for you. Each member changes only their own; API keys can't.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weeklySummary":{"description":"Get the weekly summary email","type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/keys":{"get":{"operationId":"listStorefrontKeys","tags":["Storefront API"],"summary":"List publishable keys","description":"Publishable keys (`pk_live_…`) for the public Storefront API at `/api/storefront/v1` (its own spec: `/api/storefront/v1/openapi.json`). Shows each key's start (`keyPrefix`), allowed websites and last use; the whole key is shown only when it's created.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createStorefrontKey","tags":["Storefront API"],"summary":"Create a publishable key","description":"`{ \"name\": \"bzlabs.io site\", \"allowedOrigins\": [\"https://papaswillow.com\"] }`. Returns the whole key (`key`) once; only its hash is stored. Browsers may use it only from `allowedOrigins` (https, or http://localhost); calls without an Origin header (servers) are allowed with a lower rate limit. The key reads the published store and places pickup orders; it can't call this API. Members need the owner or admin role.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"allowedOrigins":{"description":"Websites allowed to use the key from a browser, e.g. [\"https://papaswillow.com\"]. Empty: server-to-server only.","maxItems":10,"type":"array","items":{"type":"string","minLength":1,"maxLength":200}}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/storefront/keys/{id}":{"patch":{"operationId":"updateStorefrontKey","tags":["Storefront API"],"summary":"Rename a publishable key or change its websites","description":"Requires scope `write:settings`.","x-required-scope":"write:settings","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"allowedOrigins":{"maxItems":10,"type":"array","items":{"type":"string","minLength":1,"maxLength":200}}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"revokeStorefrontKey","tags":["Storefront API"],"summary":"Revoke a publishable key","description":"Every call with the key is refused from now on (401 `key_revoked`). Revoking twice is fine.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/payments/connections":{"get":{"operationId":"getPaymentConnections","tags":["Online store"],"summary":"Ways to pay in the online store","description":"Every provider (pay at pickup, UPI, Stripe, PayPal, Razorpay, Square online checkout), its connection settings, its `state` (`connected`, `needs_attention`, `not_connected`, or `not_set_up` when this server lacks the provider's platform settings) and whether shoppers can use it with the business currency and country. Credentials are never returned (`hasCredentials`, `storedCredentials` names only). `checkoutEnabled` is true when at least one is on.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"put":{"operationId":"updatePaymentConnections","tags":["Online store"],"summary":"Turn ways to pay on or off","description":"`{ \"connections\": [{ \"provider\": \"pay_at_pickup\", \"enabled\": true, \"config\": { \"holdHours\": 48 } }, { \"provider\": \"upi_direct\", \"enabled\": true, \"config\": { \"vpa\": \"shop@okicici\", \"payeeName\": \"Shop\" } }] }`. Providers not listed are unchanged. UPI needs the business currency to be INR. PayPal (`config.mode` live or sandbox, `credentials.clientId`/`clientSecret`) and Razorpay (`credentials.keyId`/`keySecret`/`webhookSecret`) keys are checked with the provider when saved; PayPal's webhook is created for you. Stripe is connected with Stripe Connect from Settings → Payments (OAuth), not here; Square online checkout uses the Square connection. Money always goes to the shop's own account. Members need the owner or admin role.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connections":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"object","properties":{"provider":{"type":"string","enum":["pay_at_pickup","upi_direct","stripe","paypal","razorpay","square"]},"enabled":{"description":"Offer this way to pay in the online store","type":"boolean"},"displayName":{"description":"Name shoppers see (defaults to the provider's)","anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"config":{"description":"Provider settings, e.g. { vpa, payeeName } for UPI, { holdHours } for pay at pickup, { mode: 'live' | 'sandbox' } for PayPal","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"credentials":{"description":"Secret keys for providers that need them (PayPal clientId/clientSecret, Razorpay keyId/keySecret/webhookSecret); stored encrypted, never returned","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","maxLength":4000}},"sortOrder":{"type":"integer","minimum":0,"maximum":100}},"required":["provider"],"additionalProperties":false}}},"required":["connections"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/payments/connections/{provider}/test":{"post":{"operationId":"testPaymentConnection","tags":["Online store"],"summary":"Test a payment connection","description":"Makes a harmless authenticated call to the provider with the stored keys. `{ ok, detail, settings }`. Refused keys mark the connection `needs_attention` and stop it being offered until fixed. Members need the owner or admin role.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/payments/connections/{provider}":{"delete":{"operationId":"disconnectPaymentProvider","tags":["Online store"],"summary":"Disconnect a way to pay","description":"Revokes SupplySynk's access where the provider supports it (Stripe Connect deauthorize; the PayPal webhook we created), forgets the keys and settings and stops offering it. Payments already recorded stay. 409 `open_checkouts` while shoppers are still paying with it; `?force=true` cancels those orders first (stock released). Only what verifies late webhooks is kept (the Stripe account id, the Razorpay webhook secret), so a late payment is still recorded and flagged for a refund. Members need the owner or admin role.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"force","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/contacts":{"get":{"operationId":"listMarketingContacts","tags":["Marketing"],"summary":"List contacts with their consent","description":"Contacts the shop may market to, newest first, each with per-channel consent (`consent.email|whatsapp|sms`: latest `status`, `suppressed`, `subscribed`). Filter with a saved `segmentId` and/or `customer` (new, repeat, lapsed with `lapsedDays`, lead), `productId`, `categoryId`, `tag`, `consent` (channel) and `search`. Members need the staff role or higher (contacts are personal data).\n\nRequires scope `read:contacts`.","x-required-scope":"read:contacts","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":200}},{"name":"segmentId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"customer","in":"query","required":false,"schema":{"type":"string","enum":["new","repeat","lapsed","lead"]}},{"name":"lapsedDays","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":3650}},{"name":"productId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"categoryId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"tag","in":"query","required":false,"schema":{"type":"string"}},{"name":"consent","in":"query","required":false,"schema":{"type":"string","enum":["email","whatsapp","sms"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createMarketingContact","tags":["Marketing"],"summary":"Add a contact","description":"Email and/or phone (phones are stored in E.164 for the business's country). Changing the email or phone of a contact who gave consent on that channel needs `manage:marketing` (managers and up) and ends that consent (event `address_changed`). No consent is recorded: add it with `POST /marketing/contacts/{id}/consents`. 409 when the email or phone is already a contact. Emits `contact.created`.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string","maxLength":254,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"phone":{"type":"string","minLength":4,"maxLength":30},"tags":{"maxItems":20,"type":"array","items":{"type":"string"}},"customerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/contacts/{id}":{"get":{"operationId":"getMarketingContact","tags":["Marketing"],"summary":"A contact with its consent history","description":"Includes every consent event (append-only: channel, status, source, the exact wording and version, when, who) and the contact's unsubscribe links per channel. Members need the staff role or higher.\n\nRequires scope `read:contacts`.","x-required-scope":"read:contacts","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateMarketingContact","tags":["Marketing"],"summary":"Update a contact","description":"Requires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":["string","null"]},"email":{"anyOf":[{"type":"string","maxLength":254,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","minLength":4,"maxLength":30},{"type":"null"}]},"tags":{"maxItems":20,"type":"array","items":{"type":"string"}}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/contacts/{id}/erase":{"post":{"operationId":"eraseMarketingContact","tags":["Marketing"],"summary":"Erase a contact's personal data","description":"`{ \"reason\": \"Asked us to delete their data\" }`. Removes name, email, phone and tags, clears IP and browser from their consent records, deletes their pending sign-ups and keeps each address only as a do-not-contact hash, so they're never messaged or imported again. Can't be undone. Members need the manager role or higher.\n\nRequires scope `manage:marketing`.","x-required-scope":"manage:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["reason"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/signups":{"get":{"operationId":"listMarketingSignups","tags":["Marketing"],"summary":"Sign-ups from the store form","description":"The store's \"Get offers\" form records requests, not consent. Email requests are confirmed by the person (double opt-in link, 7 days); WhatsApp requests wait for a manager to confirm after the person messages the shop. `status`: pending (default), confirmed, dismissed.\n\nRequires scope `read:contacts`.","x-required-scope":"read:contacts","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"schema":{"default":"pending","type":"string","enum":["pending","confirmed","dismissed"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/signups/{id}/confirm":{"post":{"operationId":"confirmMarketingSignup","tags":["Marketing"],"summary":"Confirm a WhatsApp sign-up","description":"`{ \"reason\": \"They messaged us from this number on 15 Oct\" }`. Records WhatsApp consent with the wording the person saw. Refused (409 `suppressed`) for a number that unsubscribed. Members need the manager role or higher.\n\nRequires scope `manage:marketing`.","x-required-scope":"manage:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["reason"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/signups/{id}":{"delete":{"operationId":"dismissMarketingSignup","tags":["Marketing"],"summary":"Dismiss a pending sign-up","description":"Requires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/contacts/{id}/consents":{"post":{"operationId":"recordContactConsent","tags":["Marketing"],"summary":"Record consent by hand","description":"`{ \"channel\": \"whatsapp\", \"status\": \"opted_in\", \"source\": \"Signed form at the counter\", \"reason\": \"Asked to join our offers list\" }`. Opting out also adds the address to the suppression list; a suppressed address can't be opted in again here (409 `suppressed`): only the person can, from the store's sign-up form. Audited; emits `contact.consent_changed`. Members need the manager role or higher.\n\nRequires scope `manage:marketing`.","x-required-scope":"manage:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["email","whatsapp","sms"]},"status":{"type":"string","enum":["opted_in","opted_out"]},"source":{"type":"string","minLength":3,"maxLength":200},"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["channel","status","source","reason"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/contacts/import":{"post":{"operationId":"importMarketingContacts","tags":["Marketing"],"summary":"Import contacts from CSV","description":"`{ \"csv\": \"name,email,phone,tags,email_consent,whatsapp_consent,consent_source\\n…\" }`. The `consent_source` column is required: consent is recorded only for rows that say where it came from (yes in a `*_consent` column and a non-empty source), never otherwise, and never for suppressed addresses. Existing contacts (same email or phone) are updated, not duplicated. Returns counts and the problem rows. Members need the manager role or higher.\n\nRequires scope `manage:marketing`.","x-required-scope":"manage:marketing","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"csv":{"type":"string","minLength":1,"maxLength":2000000}},"required":["csv"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/contacts/export":{"get":{"operationId":"exportMarketingContacts","tags":["Marketing"],"summary":"Export opted-in contacts as CSV or vCard","description":"Answers with a file, not JSON: `format=csv` (name, address, opted-in date, tags, unsubscribe link) or `format=vcf` (vCards to import into a phone for a WhatsApp Business broadcast list). Only contacts currently opted in to `channel` and not suppressed are included. Takes the same filters as the list. Members need the manager role or higher.\n\nRequires scope `manage:marketing`.","x-required-scope":"manage:marketing","parameters":[{"name":"customer","in":"query","required":false,"schema":{"type":"string","enum":["new","repeat","lapsed","lead"]}},{"name":"lapsedDays","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":3650}},{"name":"productId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"categoryId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"tag","in":"query","required":false,"schema":{"type":"string"}},{"name":"channel","in":"query","required":true,"schema":{"type":"string","enum":["email","whatsapp","sms"]}},{"name":"format","in":"query","required":false,"schema":{"default":"csv","type":"string","enum":["csv","vcf"]}},{"name":"segmentId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/contacts/sync-customers":{"post":{"operationId":"syncMarketingContacts","tags":["Marketing"],"summary":"Add store customers as contacts","description":"Every customer with an email or phone becomes a contact (source `store_checkout` for online shoppers), and contacts with a customer's email are linked to them. No consent is created.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/segments":{"get":{"operationId":"listMarketingSegments","tags":["Marketing"],"summary":"Saved segments","description":"Requires scope `read:marketing`.","x-required-scope":"read:marketing","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createMarketingSegment","tags":["Marketing"],"summary":"Save a segment","description":"`{ \"name\": \"Lapsed bat buyers\", \"filters\": { \"customer\": \"lapsed\", \"lapsedDays\": 120, \"categoryId\": \"…\", \"consent\": \"whatsapp\" } }`.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"filters":{"type":"object","properties":{"customer":{"type":"string","enum":["new","repeat","lapsed","lead"]},"lapsedDays":{"type":"integer","minimum":1,"maximum":3650},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"categoryId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"tag":{"type":"string"},"consent":{"type":"string","enum":["email","whatsapp","sms"]}},"additionalProperties":false}},"required":["name","filters"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/segments/{id}":{"delete":{"operationId":"deleteMarketingSegment","tags":["Marketing"],"summary":"Delete a segment","description":"Requires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/links":{"get":{"operationId":"listMarketingLinks","tags":["Marketing"],"summary":"Buy links","description":"Short links (`shortUrl`, `<business address>/go/<code>`) with their click counts.\n\nRequires scope `read:marketing`.","x-required-scope":"read:marketing","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"postId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createMarketingLink","tags":["Marketing"],"summary":"Create a buy link","description":"`target`: `product` (`productId`), `category` (`categoryId`), `store` (home page) or `url`. The link opens the shop's own store page with the UTMs given and `ss_link=<code>`, so orders are attributed to it. `url` (another website) is only for owners and admins (`manage:marketing` for keys) and must be https: links never redirect to arbitrary sites.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target":{"type":"string","enum":["product","category","store","url"]},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"categoryId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"url":{"type":"string","maxLength":2000},"label":{"type":"string","maxLength":120},"utmSource":{"type":"string","maxLength":100,"pattern":"^[\\p{L}\\p{N} ._\\-+]*$"},"utmMedium":{"type":"string","maxLength":100,"pattern":"^[\\p{L}\\p{N} ._\\-+]*$"},"utmCampaign":{"type":"string","maxLength":100,"pattern":"^[\\p{L}\\p{N} ._\\-+]*$"},"utmContent":{"type":"string","maxLength":100,"pattern":"^[\\p{L}\\p{N} ._\\-+]*$"},"postId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"network":{"type":"string","enum":["facebook","instagram","whatsapp"]}},"required":["target"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/links/{id}":{"get":{"operationId":"getMarketingLink","tags":["Marketing"],"summary":"A buy link with its results","description":"Clicks per day (last 30 days), top referring sites, and orders and revenue attributed to it (cancelled orders excluded).\n\nRequires scope `read:marketing`.","x-required-scope":"read:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"archiveMarketingLink","tags":["Marketing"],"summary":"Archive a buy link","description":"The link stops working (404); its clicks and orders stay in the results.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/results":{"get":{"operationId":"getMarketingResults","tags":["Marketing"],"summary":"Clicks, orders and revenue per link, post, campaign and source","description":"Over `from`..`to` (UTC days, default the last 30). Orders are attributed last-touch within 30 days of a tagged visit; cancelled orders don't count.\n\nRequires scope `read:marketing`.","x-required-scope":"read:marketing","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/posts":{"get":{"operationId":"listMarketingPosts","tags":["Marketing"],"summary":"Post drafts","description":"Requires scope `read:marketing`.","x-required-scope":"read:marketing","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","scheduled","publishing","published","failed"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createMarketingPost","tags":["Marketing"],"summary":"Create a post draft","description":"Text, an optional `productId` and target `networks` (facebook, instagram, whatsapp). With a product, one buy link per network is created (utm_source = network, utm_medium = social or message, utm_campaign = `campaign`, utm_content = post id). `addProductPhoto` adds the product's main photo. The response carries per-network checks (`checks`) and, for WhatsApp, a ready `whatsappShareUrl`. Publishing to Facebook and Instagram comes with the Meta connection; only drafts exist today.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"caption":{"type":"string","maxLength":5000},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"networks":{"maxItems":3,"type":"array","items":{"type":"string","enum":["facebook","instagram","whatsapp"]}},"campaign":{"type":"string","maxLength":60},"addProductPhoto":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/posts/{id}":{"get":{"operationId":"getMarketingPost","tags":["Marketing"],"summary":"A post draft with its checks and links","description":"Requires scope `read:marketing`.","x-required-scope":"read:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateMarketingPost","tags":["Marketing"],"summary":"Edit a post draft","description":"Changing the product, networks or campaign updates its buy links (old ones are archived).\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"caption":{"type":"string","maxLength":5000},"productId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"networks":{"maxItems":3,"type":"array","items":{"type":"string","enum":["facebook","instagram","whatsapp"]}},"campaign":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"imageOrder":{"maxItems":10,"type":"array","items":{"type":"string","maxLength":40}}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteMarketingPost","tags":["Marketing"],"summary":"Delete a post draft","description":"Its buy links stop working; their results stay.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/posts/{id}/images":{"post":{"operationId":"addMarketingPostImage","tags":["Marketing"],"summary":"Add a product photo or an AI image","description":"`{ \"source\": \"product\", \"productId\": \"…\", \"imageId\": \"…\" }` copies one of the product's photos; `{ \"source\": \"generate\", \"productId\": \"…\", \"style\": \"lifestyle\" }` makes one with AI from the product's own photo (marked `generated`; counts against the monthly AI image allowance; up to about 90 s). Images are stored as JPEG (at most 1440 px wide), metadata removed. Up to 10 per post.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","const":"product"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"imageId":{"type":"string","maxLength":64}},"required":["source","productId"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","const":"generate"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"style":{"default":"lifestyle","type":"string","enum":["studio","lifestyle","clean_background","custom"]},"instructions":{"type":"string","maxLength":500}},"required":["source","productId"],"additionalProperties":false}]}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/posts/{id}/images/upload":{"post":{"operationId":"uploadMarketingPostImage","tags":["Marketing"],"summary":"Upload an image to a post","description":"Multipart, up to 10 MB; stored as JPEG.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The image (JPEG, PNG, WebP or AVIF)"},"alt":{"type":"string","description":"Optional: describe the image"}}}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/posts/{id}/images/{imageId}":{"delete":{"operationId":"removeMarketingPostImage","tags":["Marketing"],"summary":"Remove an image from a post","description":"Requires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"},{"name":"imageId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/posts/{id}/images/{imageId}/instagram":{"post":{"operationId":"prepareMarketingPostImage","tags":["Marketing"],"summary":"Prepare an image for Instagram","description":"Makes an Instagram-ready JPEG copy: `fit: crop` cuts the edges, `pad` adds a border in `background`, to a shape between 4:5 and 1.91:1, at most 1440 px wide and 8 MB.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","parameters":[{"$ref":"#/components/parameters/Id"},{"name":"imageId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"fit":{"default":"pad","type":"string","enum":["crop","pad"]},"background":{"default":"#ffffff","type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/captions":{"post":{"operationId":"generateMarketingCaption","tags":["Marketing"],"summary":"Write a caption with AI","description":"`tone` (friendly, excited, premium), `language` (en, hi), `hashtags` (0-30), optional `productId`, `network` and `notes`. Prices are never invented: the product's real price, formatted for the business, is the only one that appears. Nothing is saved.\n\nRequires scope `write:marketing`.","x-required-scope":"write:marketing","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"tone":{"default":"friendly","type":"string","enum":["friendly","excited","premium"]},"language":{"default":"en","type":"string","enum":["en","hi"]},"hashtags":{"default":5,"type":"integer","minimum":0,"maximum":30},"network":{"type":"string","enum":["facebook","instagram","whatsapp"]},"notes":{"type":"string","maxLength":300}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/marketing/settings":{"get":{"operationId":"getMarketingSettings","tags":["Marketing"],"summary":"Marketing settings","description":"The store's \"Get offers\" form switch, the WhatsApp chat button (number and message), and the link page (`/links`) with its pinned links.\n\nRequires scope `read:marketing`.","x-required-scope":"read:marketing","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"put":{"operationId":"updateMarketingSettings","tags":["Marketing"],"summary":"Change marketing settings","description":"Fields are optional; only those sent change. These change the public store, so members need the owner or admin role.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"signupEnabled":{"type":"boolean"},"whatsappButtonEnabled":{"type":"boolean"},"whatsappNumber":{"anyOf":[{"type":"string","maxLength":30},{"type":"null"}]},"whatsappMessage":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"linkPageEnabled":{"type":"boolean"},"linkPageTitle":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"pinnedLinks":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":60},"linkId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},"required":["label","linkId"],"additionalProperties":false}}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/invoice":{"post":{"operationId":"issueOrderInvoice","tags":["GST documents"],"summary":"Issue the order's GST invoice","description":"India, GST-registered businesses: issues the Tax Invoice (regular GST) or Bill of Supply (composition) for an order whose tax SupplySynk worked out, numbered in the GSTIN's financial-year series (e.g. `INV/26-27/000123`). Returns the existing document if one was issued (orders get one automatically when fully fulfilled). Documents never change; corrections are credit notes. `publicUrl` is a shareable page.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/orders/{id}/gst-retry":{"post":{"operationId":"retryOrderGst","tags":["GST documents"],"summary":"Issue pending GST documents","description":"Issues whatever the order is still owed: its invoice once fully fulfilled, and credit notes for returns or a cancellation. Idempotent. When one can't be issued (e.g. a business customer's address is missing), the order keeps `gstPending` (`invoice` | `credit_note`) and `gstPendingError`; the daily maintenance retries too. Returns `{ pending, error, issued }`.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/gst/documents":{"get":{"operationId":"listGstDocuments","tags":["GST documents"],"summary":"List GST documents","description":"Tax invoices, bills of supply and credit notes, newest first; filter by issue date (`from`, `to`), `type` or `orderId`. Each has the printed `snapshot` and its `publicUrl`.\n\nRequires scope `read:orders`.","x-required-scope":"read:orders","parameters":[{"name":"from","in":"query","required":false,"description":"Issued on or after (YYYY-MM-DD)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":false,"description":"Issued on or before (YYYY-MM-DD)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["tax_invoice","bill_of_supply","credit_note"]}},{"name":"orderId","in":"query","required":false,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/gst/documents/{id}":{"get":{"operationId":"getGstDocument","tags":["GST documents"],"summary":"Get a GST document","description":"Requires scope `read:orders`.","x-required-scope":"read:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/gst/documents/{id}/credit-note":{"post":{"operationId":"createCreditNote","tags":["GST documents"],"summary":"Issue a credit note","description":"Against a tax invoice or bill of supply: for the given product quantities, or everything not yet credited. Amounts are the invoice's, prorated by quantity; its own series (`CN/26-27/000001`). Returns and cancellations of invoiced orders get one automatically.\n\nRequires scope `write:orders`.","x-required-scope":"write:orders","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"What's credited; omit to credit everything not yet credited (a full cancellation)","minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":1000000}},"required":["productId","quantity"],"additionalProperties":false}},"reason":{"default":"Return","description":"Why: a return, a cancellation, a price correction","type":"string","minLength":1,"maxLength":300}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/gst/gstr1":{"get":{"operationId":"exportGstr1","tags":["GST documents"],"summary":"GSTR-1 export (file)","description":"Answers with a file, not JSON. `period` is a month (`2026-10`) or a financial-year quarter (`2026-Q3`). `format=json` gives the GST offline tool's JSON (b2b, b2cl, b2cs, cdnr, cdnur, nil, hsn split B2B/B2C, doc_issue); `format=csv&section=b2b` one table. Built from the documents issued in the period. Check with your CA before filing.\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"period","in":"query","required":true,"description":"Month (2026-10) or financial-year quarter (2026-Q3)","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2]|Q[1-4])$"}},{"name":"gstin","in":"query","required":false,"description":"Which GSTIN; defaults to the business's","schema":{"type":"string","maxLength":20}},{"name":"format","in":"query","required":false,"schema":{"default":"json","type":"string","enum":["json","csv"]}},{"name":"section","in":"query","required":false,"description":"CSV only: b2b, b2cl, b2cs, cdnr, cdnur, hsn_b2b, hsn_b2c, docs or nil","schema":{"type":"string","enum":["b2b","b2cl","b2cs","cdnr","cdnur","hsn_b2b","hsn_b2c","docs","nil"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/gst/registers/sales":{"get":{"operationId":"exportSalesRegister","tags":["GST documents"],"summary":"Sales register (CSV file)","description":"Every GST document line issued between `from` and `to`; credit notes negative.\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"from","in":"query","required":true,"description":"First day (YYYY-MM-DD)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":true,"description":"Last day (YYYY-MM-DD)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/gst/registers/purchases":{"get":{"operationId":"exportPurchaseRegister","tags":["GST documents"],"summary":"Purchase register (CSV file)","description":"Purchase-order lines with input tax by order date. Staff and up (it shows costs).\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"from","in":"query","required":true,"description":"First day (YYYY-MM-DD)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":true,"description":"Last day (YYYY-MM-DD)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/gst/tally":{"get":{"operationId":"exportTally","tags":["GST documents"],"summary":"Tally Prime export (XML file)","description":"Answers with a file, not JSON: Tally's import XML (ENVELOPE / IMPORTDATA). Sales vouchers for the tax invoices and bills of supply issued between `from` and `to` (default: last month; one financial year at most), credit-note vouchers against their invoice, and the ledgers, units and stock items they use. `inventory=false` gives accounting-only vouchers (no stock items). `part=masters` or `part=vouchers` gives one half. Every voucher adds up to 0.00. Refused (400) above 4 MB or 3,000 documents (export a shorter range), or when a document's total differs from its parts by more than ₹1 beyond its round-off. Purchases aren't included. Members need the manager role or above. Have your CA check the first import.\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","parameters":[{"name":"from","in":"query","required":false,"description":"First day (YYYY-MM-DD); with `to`. Default: last month","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":false,"description":"Last day (YYYY-MM-DD); in the same financial year as `from`","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"period","in":"query","required":false,"description":"Instead of from/to: a month (2026-10) or financial-year quarter (2026-Q3)","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2]|Q[1-4])$"}},{"name":"gstin","in":"query","required":false,"description":"Which GSTIN's documents; defaults to the business's","schema":{"type":"string","maxLength":20}},{"name":"inventory","in":"query","required":false,"description":"true: item invoices with stock items; false: accounting only (no stock in Tally)","schema":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["0","1","true","false"]}]}},{"name":"part","in":"query","required":false,"description":"all: one file with masters, then vouchers; or either part alone","schema":{"default":"all","type":"string","enum":["all","masters","vouchers"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/gst/tally/settings":{"get":{"operationId":"getTallySettings","tags":["GST documents"],"summary":"Tally ledger names","description":"The ledger and voucher type names the Tally export uses, the defaults, and the Tally groups new ledgers go under. In names, `{rate}` becomes the GST rate (sales, IGST) or the component's rate (CGST, SGST, UTGST). Members need the manager role or above.\n\nRequires scope `read:reports`.","x-required-scope":"read:reports","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateTallySettings","tags":["GST documents"],"summary":"Change Tally ledger names","description":"Only the fields sent change; `null` (or the default itself) puts a name back to its default, and only names that differ from the defaults are stored. `{rate}` is allowed only in the sales and tax ledger names. Names must differ at every GST rate where Tally needs them to (for example the CGST and SGST ledgers). Custom voucher types must already exist in Tally. Members need the owner or admin role.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"walkInLedger":{"description":"Party ledger for sales without a GSTIN (default \"Cash\", which every Tally company has)","anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"salesLedger":{"description":"Sales ledger; \"{rate}\" becomes the GST rate (default \"Sales GST {rate}%\")","anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"billOfSupplyLedger":{"description":"Sales ledger for bills of supply (composition)","anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"cgstLedger":{"description":"\"{rate}\" becomes the CGST rate, half the GST rate (default \"Output CGST {rate}%\")","anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"sgstLedger":{"anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"utgstLedger":{"anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"igstLedger":{"anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"roundOffLedger":{"anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"deliveryLedger":{"description":"Delivery charges on bills","anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"salesVoucherType":{"anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"creditNoteVoucherType":{"anyOf":[{"type":"string","minLength":1,"maxLength":80,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},{"type":"null"}]},"b2cParty":{"description":"Sales without a GSTIN: walk_in = all to the walk-in ledger; customer = a ledger per customer name","anyOf":[{"type":"string","enum":["walk_in","customer"]},{"type":"null"}]}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/tax/settings":{"get":{"operationId":"getTaxSettings","tags":["Tax"],"summary":"Tax settings","description":"The business's tax registration (`regime`: India `none` | `composition` | `regular`; US `none` | `sales_tax`), GSTIN, legal and trade names, whether prices include tax, the default rate, bill rounding and its GST state. India also lists the GST rate slabs and the price-band rules in force.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateTaxSettings","tags":["Tax"],"summary":"Change tax settings","description":"Only the fields sent change. A GSTIN is checked (format, state code, check character); a GST-registered business (composition or regular) needs one. India's default rate must be a GST slab; US prices always exclude tax. Members need the owner or admin role. Applies to new orders only.\n\nRequires scope `write:settings`.","x-required-scope":"write:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"regime":{"type":"string","enum":["none","composition","regular","sales_tax"],"description":"India: none (unregistered), composition or regular. US: none or sales_tax"},"gstin":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"description":"India: the business's 15-character GSTIN (checked)"},"legalName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"Legal name as registered"},"tradeName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"Trade name shown on bills"},"pricesIncludeTax":{"description":"India only: prices include GST (default true). US prices always exclude tax","type":["boolean","null"]},"defaultRate":{"anyOf":[{"type":"number","minimum":0,"maximum":100},{"type":"null"}],"description":"Rate in percent for products without their own: the US sales tax rate, or India's usual GST rate"},"rounding":{"anyOf":[{"type":"string","enum":["none","nearest_1"]},{"type":"null"}],"description":"Bill rounding: none, or nearest_1 (India default: nearest ₹1)"},"invoicePrefix":{"anyOf":[{"type":"string","pattern":"^[A-Z0-9]{1,3}$"},{"type":"null"}],"description":"India: tax invoice number prefix, as in INV/26-27/000123 (default INV). Applies from the next new series"}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/tax/preview":{"get":{"operationId":"previewTax","tags":["Tax"],"summary":"Work out tax for a cart","description":"The tax breakup a cart would get (nothing is saved): per line the taxable value, rate and components (CGST, SGST/UTGST, IGST or SALES_TAX), then totals, round-off and warnings. `items` is a JSON-encoded array in the query string. Amounts are decimal strings.\n\nRequires scope `read:products`.","x-required-scope":"read:products","parameters":[{"name":"items","in":"query","required":true,"description":"JSON array of cart lines, e.g. [{\"productId\":\"…\",\"quantity\":2}]","schema":{"type":"string","maxLength":100000}},{"name":"locationId","in":"query","required":false,"description":"Selling location; defaults to the default location","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"}},{"name":"placeOfSupply","in":"query","required":false,"description":"India: state (code or name) where the supply ends; defaults to the selling location's","schema":{"type":"string","maxLength":60}},{"name":"discountAmount","in":"query","required":false,"description":"Order-level discount, spread over the lines before tax","schema":{"type":"number","minimum":0,"maximum":1000000000}},{"name":"shippingAmount","in":"query","required":false,"schema":{"type":"number","minimum":0,"maximum":1000000000}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"previewTaxPost","tags":["Tax"],"summary":"Work out tax for a cart (body)","description":"Same as GET /tax/preview with the cart in the body.\n\nRequires scope `read:products`.","x-required-scope":"read:products","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"productId":{"description":"A product: its price, rate, HSN and exemption are used unless overridden","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"unitPrice":{"description":"Defaults to the product's selling price","type":"number","minimum":0,"maximum":1000000000},"discountAmount":{"description":"Discount on the line (not per unit)","type":"number","minimum":0,"maximum":1000000000},"taxRate":{"description":"Rate (percent) for a line without a product","type":"number","minimum":0,"maximum":100},"hsn":{"type":"string","maxLength":8},"exempt":{"type":"boolean"}},"required":["quantity"],"additionalProperties":false},"description":"Cart lines"},"locationId":{"description":"Selling location; defaults to the default location","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},"placeOfSupply":{"description":"India: state (code or name) where the supply ends; defaults to the selling location's","type":"string","maxLength":60},"discountAmount":{"description":"Order-level discount, spread over the lines before tax","type":"number","minimum":0,"maximum":1000000000},"shippingAmount":{"type":"number","minimum":0,"maximum":1000000000}},"required":["items"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/ai/connection":{"get":{"operationId":"getAiConnection","tags":["AI"],"summary":"Where to connect an AI app","description":"`mcpUrl` is this business's own MCP address (`/api/mcp/<slug>`): Claude or ChatGPT connected there need no organization picker. `sharedMcpUrl` (`/api/mcp`) also works, with the picker. `tiers` lists the access levels a person chooses when connecting: read (look only), act (routine changes run, high-impact ones wait for approval) and approval (every change waits).\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/ai/connections":{"get":{"operationId":"listAiConnections","tags":["AI"],"summary":"Every AI app connected to this business","description":"Who connected which app, its access level (`tier`) and scopes. `app` is the app's name, marked \"(unverified, <host>)\" unless it returns only to a known MCP client host. Owners and admins signed in to SupplySynk only.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"lowerAiConnectionTier","tags":["AI"],"summary":"Lower a member's AI access level","description":"Owners and admins can lower (never raise) another member's connection: act > approval > read. Lowering to read turns down that connection's waiting requests.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","minLength":1,"maxLength":255},"clientId":{"type":"string","minLength":1,"maxLength":255},"tier":{"type":"string","enum":["read","act","approval"]}},"required":["userId","clientId","tier"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/ai/connections/disconnect":{"post":{"operationId":"disconnectAiConnection","tags":["AI"],"summary":"Disconnect a member's AI app","description":"Removes the app's consent for this business, revokes its tokens here and turns down its waiting requests. Owners and admins.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","minLength":1,"maxLength":255},"clientId":{"type":"string","minLength":1,"maxLength":255}},"required":["userId","clientId"],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/approvals":{"get":{"operationId":"listApprovals","tags":["AI"],"summary":"AI actions waiting for approval","description":"Requests from AI apps (OAuth connections) that need a person: `status` pending, approved (with `result`), rejected (with `rejectReason`), expired (after 7 days) or failed (with `error`). Owners, admins and managers (and API keys) see all of them; other members only their own.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"status","in":"query","required":false,"description":"One status, or \"decided\" for everything no longer pending. Default: every status, newest first","schema":{"type":"string","enum":["pending","executing","approved","rejected","expired","failed","decided"]}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/approvals/{id}":{"get":{"operationId":"getApproval","tags":["AI"],"summary":"Get an approval request","description":"Requires scope `read:settings`.","x-required-scope":"read:settings","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/approvals/{id}/approve":{"post":{"operationId":"approveApproval","tags":["AI"],"summary":"Approve and run an AI action","description":"Runs the requested tool once, recorded as approved by the caller, and returns the request with its `result` (status `approved`) or `error` (status `failed`). Only owners, admins and managers signed in to SupplySynk; API keys and AI apps get 403. The approver must also be allowed to do the action. 409 if it was already decided or expired.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/approvals/{id}/reject":{"post":{"operationId":"rejectApproval","tags":["AI"],"summary":"Reject an AI action","description":"Owners, admins and managers signed in to SupplySynk. The AI sees `rejectReason`.\n\nRequires scope `read:settings`.","x-required-scope":"read:settings","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/customers":{"get":{"operationId":"listCustomers","tags":["Customers"],"summary":"List customers","description":"Requires scope `read:customers`.","x-required-scope":"read:customers","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createCustomer","tags":["Customers"],"summary":"Create a customer","description":"Requires scope `write:customers`.","x-required-scope":"write:customers","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"email":{"anyOf":[{"type":"string","maxLength":320,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"company":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"billingAddress":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"shippingAddress":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"tags":{"maxItems":50,"type":"array","items":{"type":"string","maxLength":50}}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/customers/{id}":{"get":{"operationId":"getCustomer","tags":["Customers"],"summary":"Get a customer","description":"Requires scope `read:customers`.","x-required-scope":"read:customers","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateCustomer","tags":["Customers"],"summary":"Update a customer","description":"Requires scope `write:customers`.","x-required-scope":"write:customers","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"email":{"anyOf":[{"type":"string","maxLength":320,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"company":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"billingAddress":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"shippingAddress":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"tags":{"maxItems":50,"type":"array","items":{"type":"string","maxLength":50}}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCustomer","tags":["Customers"],"summary":"Delete a customer","description":"Returns 409 when the record is still referenced.\n\nRequires scope `write:customers`.","x-required-scope":"write:customers","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/suppliers":{"get":{"operationId":"listSuppliers","tags":["Suppliers"],"summary":"List suppliers","description":"Requires scope `read:suppliers`.","x-required-scope":"read:suppliers","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createSupplier","tags":["Suppliers"],"summary":"Create a supplier","description":"Requires scope `write:suppliers`.","x-required-scope":"write:suppliers","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"code":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"contactName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"email":{"anyOf":[{"type":"string","maxLength":320,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"website":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"description":"A bare hostname like example.com is stored as https://example.com"},"address":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"paymentTerms":{"anyOf":[{"type":"integer","minimum":0,"maximum":365},{"type":"null"}]},"currency":{"anyOf":[{"type":"string","minLength":3,"maxLength":3},{"type":"null"}]},"avgLeadTimeDays":{"anyOf":[{"type":"integer","minimum":0,"maximum":365},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"status":{"type":"string","enum":["active","inactive","pending"]}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/suppliers/{id}":{"get":{"operationId":"getSupplier","tags":["Suppliers"],"summary":"Get a supplier","description":"Requires scope `read:suppliers`.","x-required-scope":"read:suppliers","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateSupplier","tags":["Suppliers"],"summary":"Update a supplier","description":"Requires scope `write:suppliers`.","x-required-scope":"write:suppliers","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"code":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"contactName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"email":{"anyOf":[{"type":"string","maxLength":320,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"website":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"description":"A bare hostname like example.com is stored as https://example.com"},"address":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"paymentTerms":{"anyOf":[{"type":"integer","minimum":0,"maximum":365},{"type":"null"}]},"currency":{"anyOf":[{"type":"string","minLength":3,"maxLength":3},{"type":"null"}]},"avgLeadTimeDays":{"anyOf":[{"type":"integer","minimum":0,"maximum":365},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"status":{"type":"string","enum":["active","inactive","pending"]}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteSupplier","tags":["Suppliers"],"summary":"Delete a supplier","description":"Returns 409 when the record is still referenced.\n\nRequires scope `write:suppliers`.","x-required-scope":"write:suppliers","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/locations":{"get":{"operationId":"listLocations","tags":["Locations"],"summary":"List locations","description":"Requires scope `read:locations`.","x-required-scope":"read:locations","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createLocation","tags":["Locations"],"summary":"Create a location","description":"Requires scope `write:locations`.","x-required-scope":"write:locations","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"type":{"type":"string","enum":["warehouse","store","supplier","dropship"]},"address":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"isActive":{"type":"boolean"},"gstin":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"description":"India: GSTIN of this place of business, if it has its own (default: the business's)"},"stateCode":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"description":"India: GST state (code or name) of this place; default from the GSTIN or the address"}},"required":["name","type"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/locations/{id}":{"get":{"operationId":"getLocation","tags":["Locations"],"summary":"Get a location","description":"Requires scope `read:locations`.","x-required-scope":"read:locations","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateLocation","tags":["Locations"],"summary":"Update a location","description":"Requires scope `write:locations`.","x-required-scope":"write:locations","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"type":{"type":"string","enum":["warehouse","store","supplier","dropship"]},"address":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"isActive":{"type":"boolean"},"gstin":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"description":"India: GSTIN of this place of business, if it has its own (default: the business's)"},"stateCode":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"description":"India: GST state (code or name) of this place; default from the GSTIN or the address"}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteLocation","tags":["Locations"],"summary":"Delete a location","description":"Returns 409 when the record is still referenced.\n\nRequires scope `write:locations`.","x-required-scope":"write:locations","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/categories":{"get":{"operationId":"listCategories","tags":["Categories"],"summary":"List categories","description":"Requires scope `read:categories`.","x-required-scope":"read:categories","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":100000}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Page"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createCategory","tags":["Categories"],"summary":"Create a category","description":"Requires scope `write:categories`.","x-required-scope":"write:categories","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"sortOrder":{"type":"integer","minimum":0,"maximum":100000}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/categories/{id}":{"get":{"operationId":"getCategory","tags":["Categories"],"summary":"Get a category","description":"Requires scope `read:categories`.","x-required-scope":"read:categories","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateCategory","tags":["Categories"],"summary":"Update a category","description":"Requires scope `write:categories`.","x-required-scope":"write:categories","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"sortOrder":{"type":"integer","minimum":0,"maximum":100000}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCategory","tags":["Categories"],"summary":"Delete a category","description":"Returns 409 when the record is still referenced.\n\nRequires scope `write:categories`.","x-required-scope":"write:categories","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ssk_…","description":"API secret key: `Authorization: Bearer ssk_…`"},"basicAuth":{"type":"http","scheme":"basic","description":"`Authorization: Basic base64(clientId:clientSecret)`"}},"parameters":{"Id":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Unique key (≤255 chars) for safely retrying a create. A retry with the same key and body returns the original result; a different body returns 409.","schema":{"type":"string","maxLength":255}}},"headers":{"X-Request-Id":{"description":"Request identifier; include it when contacting support","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer"}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","examples":["invalid_request","forbidden","not_found","conflict","insufficient_stock"]},"message":{"type":"string"},"details":{"description":"Field errors (400) or extra context (409)"},"request_id":{"type":"string"}}}}},"Page":{"type":"object","required":["data","total","limit","offset"],"properties":{"data":{"type":"array","items":{}},"total":{"type":"integer"},"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0}}}},"responses":{"BadRequest":{"description":"Invalid input; `details` holds field errors","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid credentials","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Authenticated but missing the required scope","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Not found in this organization","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"State conflict (e.g. insufficient stock, invalid status, idempotency key reuse)","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"Unexpected server error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"x-scopes":{"read:products":"Read product information, including inventory levels","write:products":"Create, update, and delete products","read:inventory":"Read inventory levels and movements","write:inventory":"Update inventory levels, record movements","read:orders":"Read order information and history","write:orders":"Create and update orders","read:customers":"Read customer information","write:customers":"Create, update, and delete customers","read:suppliers":"Read supplier information","write:suppliers":"Create, update, and delete suppliers","read:locations":"Read location and warehouse data","write:locations":"Create and manage locations","read:categories":"Read product categories","write:categories":"Create, update, and delete categories","read:purchase_orders":"Read purchase orders and receipts","write:purchase_orders":"Create, send, receive and cancel purchase orders","read:reports":"Access analytics, reports, and forecasts","read:ai-insights":"Read AI-generated insights","write:ai-insights":"Generate new AI insights","manage:webhooks":"Configure webhook endpoints","manage:integrations":"Map locations for, and disconnect, connected systems such as Square","read:settings":"Read business settings such as whether the online store is published","write:settings":"Change business settings such as publishing the online store","read:marketing":"Read post drafts, buy links, segments and their results (not contacts)","read:contacts":"Read marketing contacts: names, emails, phones and their consent (personal data)","write:marketing":"Draft posts, write AI captions, create buy links and add contacts","manage:marketing":"Import, export and erase contacts, change their consent or address by hand (with a reason), and link to other websites"}}