{"openapi":"3.0.0","info":{"title":"Mooly Product API","version":"1.0.0","description":"Public API for product catalog management.\n\nUse this API to create, read, update, delete, and synchronize products and\nvariants from any external system (POS, ERP, spreadsheet automation, custom\nstorefront, headless commerce, …).\n\n## Product CRUD + Sync Flow\n\n1. Create an API key in dashboard Settings with the `products` permission.\n2. `POST /products` to create products and (optionally) variants.\n3. Store the returned `id` and variant `id` or `sku` in the external system.\n4. `PUT /products/{id}` for product profile updates.\n5. Variant endpoints handle price, SKU, options, and inventory updates.\n6. Product changes are propagated to linked chatbot catalogs automatically.\n\n## Recommended Product Payload\n\n```json\n{\n  \"name\": \"Basic T-shirt\",\n  \"description\": \"Short customer-facing description\",\n  \"product_type\": \"physical\",\n  \"status\": \"active\",\n  \"images\": [\"https://example.com/t-shirt.jpg\"],\n  \"unit\": \"piece\",\n  \"variants\": [\n    {\n      \"sku\": \"TSHIRT-BASIC-M-BLACK\",\n      \"name\": \"Size M / Black\",\n      \"price\": 199000,\n      \"currency\": \"VND\",\n      \"quantity\": 25,\n      \"option_values\": { \"Size\": \"M\", \"Color\": \"Black\" }\n    }\n  ]\n}\n```\n\n## Authentication\n\nAll requests require an `X-API-Key` header with a key that has the\n`products` permission.\n\n```\nX-API-Key: <your_api_key>\n```\n\n### Create an API Key\n\n1. Sign in to the dashboard.\n2. Open Settings → API Keys.\n3. Create a key with `products` permission.\n4. Copy the key immediately — it is shown **only once**.\n\n## Rate Limiting\n\n- **60 requests / minute** per API key.\n- Inspect `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers.\n\n## Response Envelope\n\nSuccess:\n\n```json\n{ \"success\": true, \"data\": { ... } }\n```\n\nError:\n\n```json\n{ \"success\": false, \"error\": \"Human-readable message\" }\n```\n\n## Common Limits\n\n| Field | Limit |\n|---|---|\n| `name` | 255 characters |\n| `images[]` | 20 entries |\n| `variants[]` per create | 50 entries |\n| `/products/bulk-delete.ids[]` | 100 entries |\n| `GET /products?limit` | 100 maximum |"},"servers":[{"url":"https://mooly.vn/api/v1","description":"Mooly"}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"products\" permission. Obtain one from dashboard Settings → API Keys."},"chatbotApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"chatbots\" permission. Obtain one from dashboard Settings → API Keys."},"ordersReadKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"orders:read\" permission."},"ordersWriteKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"orders:write\" permission."},"leadsReadKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"leads:read\" permission."},"leadsWriteKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"leads:write\" permission."},"customersReadKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"customers:read\" permission."},"customersWriteKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"customers:write\" permission."},"campaignsReadKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"campaigns:read\" permission."},"campaignsWriteKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"campaigns:write\" permission."},"analyticsReadKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"analytics:read\" permission."},"labelsReadKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"labels:read\" permission."},"labelsWriteKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"labels:write\" permission. Requires follow_up_automation feature."},"followUpReadKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"follow-up:read\" permission."},"followUpWriteKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key with the \"follow-up:write\" permission. Requires follow_up_automation feature."}},"schemas":{"Product":{"type":"object","description":"A customer product with optional variants and chatbot sync metadata.","properties":{"id":{"type":"string","format":"uuid"},"location_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"page_description":{"type":"string","nullable":true,"description":"Markdown content"},"product_type":{"type":"string","enum":["physical","digital","service"]},"status":{"type":"string","enum":["active","draft","archived"]},"images":{"type":"array","items":{"type":"string"},"nullable":true},"category_id":{"type":"string","format":"uuid","nullable":true},"unit":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"product_variants":{"type":"array","items":{"$ref":"#/components/schemas/ProductVariant"}}}},"ProductVariant":{"type":"object","description":"Sellable product variant. Use variants for SKU, price, stock, and options.","properties":{"id":{"type":"string","format":"uuid"},"product_id":{"type":"string","format":"uuid"},"sku":{"type":"string"},"name":{"type":"string"},"price":{"type":"number"},"compare_at_price":{"type":"number","nullable":true},"currency":{"type":"string","default":"VND"},"quantity":{"type":"integer"},"track_inventory":{"type":"boolean"},"allow_oversell":{"type":"boolean"},"is_active":{"type":"boolean"},"option_values":{"type":"object","additionalProperties":{"type":"string"},"nullable":true,"description":"e.g. {\"Size\": \"M\", \"Color\": \"Blue\"}"},"image_url":{"type":"string","nullable":true}}},"ErrorResponse":{"type":"object","description":"Standard error envelope returned by every endpoint.","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Product not found"}}},"SuccessMessage":{"type":"object","description":"Generic success envelope used by delete/no-content style operations.","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"type":"string","example":"Product deleted"}}}}},"Chatbot":{"type":"object","description":"A chatbot with its type, status, and non-sensitive config subset.","properties":{"id":{"type":"string","format":"uuid"},"location_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"chatbot_type":{"type":"string","enum":["sales","lead_generation","support"]},"status":{"type":"string","enum":["active","draft"]},"is_active":{"type":"boolean"},"config":{"type":"object","description":"Non-sensitive config subset. system_prompt excluded.","properties":{"default_language":{"type":"string","enum":["vi","en","auto"]},"country_code":{"type":"string"},"message_delay_seconds":{"type":"number"},"shop_prompt_v2_enabled":{"type":"boolean"}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Order":{"type":"object","description":"An order created via chatbot or REST API. internal_note is excluded from all public responses.","properties":{"id":{"type":"string","format":"uuid"},"order_number":{"type":"string"},"status":{"type":"string","enum":["pending","confirmed","processing","shipped","delivered","returned","cancelled","merged"]},"payment_status":{"type":"string","nullable":true},"subtotal":{"type":"number"},"discount":{"type":"number"},"shipping_fee":{"type":"number"},"total":{"type":"number"},"payment_method":{"type":"string","nullable":true},"shipping_address":{"type":"object","nullable":true},"customer_note":{"type":"string","nullable":true},"created_by":{"type":"string","nullable":true},"session_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"chat_order_items":{"type":"array","items":{"$ref":"#/components/schemas/OrderItem"}}}},"OrderItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"product_id":{"type":"string","format":"uuid"},"product_name":{"type":"string"},"product_price":{"type":"number"},"quantity":{"type":"integer"},"subtotal":{"type":"number"},"variant":{"type":"object","nullable":true}}},"OrderItemInput":{"type":"object","required":["product_id","product_name","product_price","quantity"],"properties":{"product_id":{"type":"string","format":"uuid"},"product_name":{"type":"string"},"product_price":{"type":"number","minimum":0},"quantity":{"type":"integer","minimum":1},"variant":{"type":"object"}}},"Lead":{"type":"object","description":"A lead captured by a chatbot conversation.","properties":{"id":{"type":"string","format":"uuid"},"chatbot_id":{"type":"string","format":"uuid"},"session_id":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"interest":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"qualification":{"type":"string","nullable":true},"custom_fields":{"type":"object","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Customer":{"type":"object","description":"A customer profile created from chatbot conversations.","properties":{"id":{"type":"string","format":"uuid"},"chatbot_id":{"type":"string","format":"uuid"},"contact_id":{"type":"string","nullable":true},"name":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"preferences":{"type":"object","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Channel":{"type":"object","description":"A messaging channel (inbox) linked to this location.","properties":{"id":{"type":"integer","description":"Chatwoot inbox ID"},"name":{"type":"string"},"channel_type":{"type":"string","example":"Channel::WebWidget"},"website_url":{"type":"string","nullable":true},"website_token":{"type":"string","nullable":true},"widget_color":{"type":"string","nullable":true},"avatar_url":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true}}},"FieldDefinition":{"type":"object","description":"Custom product field definition for a shop (location-scoped).","properties":{"id":{"type":"string","format":"uuid"},"location_id":{"type":"string","format":"uuid","nullable":true},"chatbot_id":{"type":"string","format":"uuid","nullable":true},"field_key":{"type":"string","description":"Lowercase snake_case identifier, e.g. \"material\""},"field_type":{"type":"string","description":"text | number | boolean | select | multi_select | date | url"},"field_label":{"type":"string"},"filter_type":{"type":"string","nullable":true},"is_filterable":{"type":"boolean"},"is_vectorized":{"type":"boolean"},"is_required":{"type":"boolean"},"display_order":{"type":"integer","nullable":true},"category_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Webhook":{"type":"object","description":"Outgoing webhook configuration for a chatbot.","properties":{"id":{"type":"string","format":"uuid"},"chatbot_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"url":{"type":"string","format":"uri"},"is_active":{"type":"boolean"},"event_types":{"type":"array","items":{"type":"string"}},"webhook_type":{"type":"string","enum":["custom","meta_capi"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"WebhookLog":{"type":"object","description":"Execution log entry for an outgoing webhook delivery attempt.","properties":{"id":{"type":"string","format":"uuid"},"webhook_id":{"type":"string","format":"uuid"},"event_type":{"type":"string"},"status":{"type":"string","enum":["success","failed","pending"]},"http_status":{"type":"integer","nullable":true},"error_message":{"type":"string","nullable":true},"is_test":{"type":"boolean"},"executed_at":{"type":"string","format":"date-time"}}},"Campaign":{"type":"object","description":"A broadcast campaign that sends messages to matching contacts.","properties":{"id":{"type":"string","format":"uuid"},"chatbot_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","scheduled","running","paused","completed","cancelled"]},"scheduled_at":{"type":"string","format":"date-time","nullable":true},"inbox_ids":{"type":"array","items":{"type":"string"}},"label_filters":{"type":"array","items":{"type":"string"},"nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"VariantInput":{"type":"object","description":"Variant payload used when creating a product or adding variants.","properties":{"sku":{"type":"string","description":"Auto-generated if empty"},"name":{"type":"string"},"price":{"type":"number","default":0},"compare_at_price":{"type":"number"},"currency":{"type":"string","default":"VND"},"quantity":{"type":"integer","default":0},"option_values":{"type":"object","additionalProperties":{"type":"string"},"description":"e.g. {\"Size\": \"M\", \"Color\": \"Blue\"}"},"image_url":{"type":"string"},"track_inventory":{"type":"boolean","default":true},"allow_oversell":{"type":"boolean","default":false},"is_active":{"type":"boolean","default":true}}}}},"security":[{"apiKeyAuth":[]}],"tags":[{"name":"Products","description":"Product CRUD, variants, inventory, and chatbot catalog sync"},{"name":"Chatbots","description":"Chatbot management (CRUD, config validation, test runs)"},{"name":"Orders","description":"Order management (list, get, create headless, update, update-status)"},{"name":"Leads","description":"Lead read, update, and export for CRM sync"},{"name":"Customers","description":"Customer profile read and update"},{"name":"Channels","description":"Channel (inbox) management and bot activation"},{"name":"FieldDefinitions","description":"Custom product field schema per shop (location-scoped)"},{"name":"Webhooks","description":"Outgoing webhook configuration for chatbot events"},{"name":"Campaigns","description":"Broadcast campaign management and execution control"},{"name":"Analytics","description":"Chatbot performance metrics and tool usage (read-only)"},{"name":"Labels","description":"Customer label CRUD — requires follow_up_automation feature for writes"},{"name":"FollowUp","description":"Follow-up scenario and AI config management — requires follow_up_automation feature for writes"}],"x-tagGroups":[{"name":"Catalog","tags":["Products"]},{"name":"Chatbots","tags":["Chatbots","Channels","FieldDefinitions","Webhooks"]},{"name":"Commerce","tags":["Orders"]},{"name":"CRM","tags":["Leads","Customers"]},{"name":"Campaigns","tags":["Campaigns"]},{"name":"Analytics","tags":["Analytics"]},{"name":"Follow-up","tags":["Labels","FollowUp"]}],"paths":{"/analytics/summary":{"get":{"summary":"Location-wide analytics summary","description":"Aggregate conversion metrics across all chatbots in this location for a date range.","tags":["Analytics"],"security":[{"analyticsReadKeyAuth":[]}],"parameters":[{"in":"query","name":"from","required":true,"schema":{"type":"string","format":"date-time"},"description":"Period start (ISO 8601)"},{"in":"query","name":"to","required":true,"schema":{"type":"string","format":"date-time"},"description":"Period end (ISO 8601)"}],"responses":{"200":{"description":"Analytics summary per chatbot"},"400":{"description":"Invalid date format"},"401":{"description":"Missing or invalid API key"}}}},"/analytics/chatbots/{id}":{"get":{"summary":"Per-chatbot analytics","description":"Conversion metrics for a specific chatbot. Returns cached analytics or triggers fresh aggregation for the requested date range.","tags":["Analytics"],"security":[{"analyticsReadKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"from","schema":{"type":"string","format":"date-time"},"description":"Period start (ISO 8601). If omitted, returns latest cached row."},{"in":"query","name":"to","schema":{"type":"string","format":"date-time"},"description":"Period end (ISO 8601). Required when from is provided."}],"responses":{"200":{"description":"Chatbot metrics"},"400":{"description":"Invalid date or UUID format"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Chatbot not found or not owned by this location"}}}},"/analytics/tool-usage":{"get":{"summary":"Tool call frequency","description":"Count of each bot tool called within a date range, optionally scoped to one chatbot.","tags":["Analytics"],"security":[{"analyticsReadKeyAuth":[]}],"parameters":[{"in":"query","name":"chatbot_id","schema":{"type":"string","format":"uuid"},"description":"Scope to one chatbot (must belong to this location)"},{"in":"query","name":"from","required":true,"schema":{"type":"string","format":"date-time"}},{"in":"query","name":"to","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Tool name → call count map"},"400":{"description":"Invalid date format"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Chatbot not found or cross-location"}}}},"/campaigns":{"get":{"summary":"List campaigns","description":"List broadcast campaigns for this location with optional chatbot and status filters.","tags":["Campaigns"],"security":[{"campaignsReadKeyAuth":[]}],"parameters":[{"in":"query","name":"chatbot_id","schema":{"type":"string","format":"uuid"},"description":"Filter to a specific chatbot (must belong to this location)"},{"in":"query","name":"status","schema":{"type":"string","enum":["draft","scheduled","running","paused","completed","cancelled"]}}],"responses":{"200":{"description":"List of campaigns","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}}}}}}}}},"post":{"summary":"Create campaign","description":"Create a new broadcast campaign in draft state.","tags":["Campaigns"],"security":[{"campaignsWriteKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chatbot_id","account_id","name","inbox_ids","variants"],"properties":{"chatbot_id":{"type":"string","format":"uuid"},"account_id":{"type":"string","description":"Chatwoot account ID"},"name":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time","description":"ISO 8601 — schedule for future; omit for manual start"},"inbox_ids":{"type":"array","items":{"type":"string"}},"label_filters":{"type":"array","items":{"type":"string"}},"variants":{"type":"array","description":"Message variants for A/B testing","items":{"type":"object"}}}}}}},"responses":{"201":{"description":"Campaign created in draft state"},"400":{"description":"Missing required fields or validation error"},"403":{"description":"Chatbot not owned by this location"}}}},"/campaigns/{id}":{"get":{"summary":"Get campaign","description":"Get a single campaign by ID.","tags":["Campaigns"],"security":[{"campaignsReadKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Campaign detail","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Campaign"}}}}}},"403":{"description":"Not owned by this location"},"404":{"description":"Campaign not found"}}}},"/campaigns/{id}/start":{"post":{"summary":"Start campaign","description":"**DESTRUCTIVE ACTION**: Starts sending broadcast messages to all matching\ncontacts immediately. Campaign must be in draft or scheduled status.\nVerify the target audience and message variants before calling.\n","tags":["Campaigns"],"security":[{"campaignsWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Campaign started"},"400":{"description":"Campaign not in a startable state"},"403":{"description":"Not owned by this location"}}}},"/campaigns/{id}/pause":{"post":{"summary":"Pause campaign","description":"Pause a running campaign. Resume with POST /{id}/resume.","tags":["Campaigns"],"security":[{"campaignsWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Campaign paused"},"400":{"description":"Campaign not in a pausable state"}}}},"/campaigns/{id}/resume":{"post":{"summary":"Resume campaign","description":"Resume a paused campaign.","tags":["Campaigns"],"security":[{"campaignsWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Campaign resumed"}}}},"/campaigns/{id}/cancel":{"post":{"summary":"Cancel campaign","description":"Cancel a campaign. This action cannot be undone.","tags":["Campaigns"],"security":[{"campaignsWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Campaign cancelled"}}}},"/campaigns/{id}/contacts":{"get":{"summary":"Get campaign contacts","description":"List contacts targeted by this campaign with their delivery status.","tags":["Campaigns"],"security":[{"campaignsReadKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"status","schema":{"type":"string"},"description":"Filter by delivery status"},{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":50,"maximum":100}}],"responses":{"200":{"description":"Campaign contacts list"}}}},"/channels":{"get":{"summary":"List channels","description":"List all messaging channels (inboxes) for this location.","tags":["Channels"],"security":[{"chatbotApiKeyAuth":[]}],"responses":{"200":{"description":"List of channels","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/channels/website":{"post":{"summary":"Create website channel","description":"Create a web widget channel for this location. Does not create ghl_locations.","tags":["Channels"],"security":[{"chatbotApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","website_url"],"properties":{"name":{"type":"string","maxLength":80},"website_url":{"type":"string"},"widget_color":{"type":"string","description":"Hex color, e.g. \"#8b5cf6\""},"welcome_title":{"type":"string"},"welcome_tagline":{"type":"string"}}}}}},"responses":{"201":{"description":"Channel created"},"400":{"description":"Validation error or subscription limit reached"},"502":{"description":"Upstream messaging provider error"}}}},"/channels/{inboxId}/activate":{"post":{"summary":"Activate bot on channel","description":"Link a chatbot to a channel and activate bot responses.","tags":["Channels"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"inboxId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chatbot_id"],"properties":{"chatbot_id":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Bot activated"},"400":{"description":"Missing params or messaging account not configured"},"403":{"description":"Chatbot not owned by this location or limit reached"}}}},"/channels/{inboxId}/deactivate":{"post":{"summary":"Deactivate bot on channel","description":"Remove bot from a channel — channel remains, bot responses stop.","tags":["Channels"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"inboxId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Bot deactivated"}}}},"/channels/{inboxId}":{"delete":{"summary":"Delete channel","description":"Delete a messaging channel. For Zalo/TikTok channels disconnect first via their respective integrations.","tags":["Channels"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"inboxId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Channel deleted"},"400":{"description":"Messaging account not configured"}}}},"/chatbots":{"get":{"summary":"List chatbots","description":"List chatbots for the authenticated location with optional status filter and pagination.","tags":["Chatbots"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["active","draft"]},"description":"Filter by chatbot status"},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"offset","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Paginated list of chatbots","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"chatbots":{"type":"array","items":{"$ref":"#/components/schemas/Chatbot"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"API key lacks 'chatbots' permission"}}},"post":{"summary":"Create a chatbot","description":"Create a new chatbot. Subscription chatbot limit is enforced.\nBot starts active with default config — configure via PATCH or dashboard.\n","tags":["Chatbots"],"security":[{"chatbotApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":100,"description":"Display name for the chatbot"},"chatbot_type":{"type":"string","enum":["sales","lead_generation","support"],"default":"sales"},"default_language":{"type":"string","enum":["vi","en","auto"],"default":"vi"}}}}}},"responses":{"201":{"description":"Chatbot created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Chatbot"}}}}}},"400":{"description":"Invalid input"},"403":{"description":"Subscription chatbot limit reached or missing permission"}}}},"/chatbots/{id}":{"get":{"summary":"Get chatbot details","description":"Get full chatbot details including product and FAQ counts.","tags":["Chatbots"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Chatbot details with stats","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"allOf":[{"$ref":"#/components/schemas/Chatbot"},{"type":"object","properties":{"product_count":{"type":"integer"},"faq_count":{"type":"integer"}}}]}}}}}},"400":{"description":"Invalid ID format"},"404":{"description":"Chatbot not found or not owned by this location"}}},"patch":{"summary":"Update chatbot","description":"Patch-merge chatbot fields. Config is deep-merged with existing values.\n`system_prompt` is intentionally excluded from the public API — manage via dashboard.\n","tags":["Chatbots"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"is_active":{"type":"boolean"},"chatbot_type":{"type":"string","enum":["sales","lead_generation","support"]},"config":{"type":"object","description":"Partial config object. system_prompt is ignored for security."}}}}}},"responses":{"200":{"description":"Chatbot updated"},"400":{"description":"Invalid input or nothing to update"},"404":{"description":"Chatbot not found"}}},"delete":{"summary":"Delete chatbot","description":"Permanently delete a chatbot and all associated data. Irreversible.","tags":["Chatbots"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Chatbot deleted"},"404":{"description":"Chatbot not found"}}}},"/chatbots/{id}/validate":{"post":{"summary":"Validate chatbot config","description":"Run health checks on the chatbot configuration.\nReturns a health status: PRODUCTION_READY | NEEDS_ATTENTION | NOT_READY\nwith per-check pass/warning/critical results.\n","tags":["Chatbots"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Validation result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"health":{"type":"string","enum":["PRODUCTION_READY","NEEDS_ATTENTION","NOT_READY"]},"summary":{"type":"object","properties":{"critical":{"type":"integer"},"warning":{"type":"integer"},"pass":{"type":"integer"}}},"checks":{"type":"array","items":{"type":"object","properties":{"check":{"type":"string"},"status":{"type":"string","enum":["pass","warning","critical"]},"message":{"type":"string"}}}}}}}}}}},"404":{"description":"Chatbot not found"}}}},"/chatbots/{id}/test-runs":{"post":{"summary":"Trigger test suite","description":"Trigger the test suite for a chatbot. Runs synchronously and returns the\nfull run summary. The same run is retrievable later via\n`GET /chatbots/{id}/test-runs/{runId}`.\n\n**Prerequisite:** chatbot must have at least one active test case (created via dashboard).\n","tags":["Chatbots"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Test run completed. Returns the full run summary.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","description":"Test run summary (run ID, status, per-case results)"}}}}}},"400":{"description":"No active test cases configured"},"404":{"description":"Chatbot not found"}}}},"/chatbots/{id}/test-runs/{runId}":{"get":{"summary":"Get test run result","description":"Poll a test run by its ID. Returns status and per-case results when complete.","tags":["Chatbots"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Chatbot ID"},{"in":"path","name":"runId","required":true,"schema":{"type":"string","format":"uuid"},"description":"Test run ID returned by POST /test-runs"}],"responses":{"200":{"description":"Test run details with per-case results"},"400":{"description":"Invalid ID format"},"404":{"description":"Chatbot or test run not found"}}}},"/customers":{"get":{"summary":"List customers","description":"List customer profiles for this location with optional chatbot filter and pagination.","tags":["Customers"],"security":[{"customersReadKeyAuth":[]}],"parameters":[{"in":"query","name":"chatbot_id","schema":{"type":"string","format":"uuid"},"description":"Filter to a specific chatbot (must belong to this location)"},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"offset","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Paginated list of customers","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"customers":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"Key lacks customers:read permission"}}}},"/customers/{id}":{"get":{"summary":"Get customer","description":"Get a single customer profile by ID including preferences.","tags":["Customers"],"security":[{"customersReadKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Customer profile","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Customer"}}}}}},"404":{"description":"Customer not found"}}},"patch":{"summary":"Update customer","description":"Update customer PII fields: name, phone, email, address.\npreferences are managed by bot runtime and excluded from this endpoint.\n","tags":["Customers"],"security":[{"customersWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"address":{"type":"string"}}}}}},"responses":{"200":{"description":"Customer updated"},"404":{"description":"Customer not found"}}}},"/field-definitions":{"get":{"summary":"List field definitions","description":"List custom product field definitions for this location.","tags":["FieldDefinitions"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"query","name":"category_id","schema":{"type":"string","format":"uuid"},"description":"Filter by product category"}],"responses":{"200":{"description":"List of field definitions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FieldDefinition"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create field definition","description":"Create a custom product field definition for this location.","tags":["FieldDefinitions"],"security":[{"chatbotApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["field_key","field_type","field_label"],"properties":{"field_key":{"type":"string","description":"Lowercase alphanumeric + underscores, e.g. \"material\""},"field_type":{"type":"string","description":"One of the valid field types (text, number, boolean, etc.)"},"field_label":{"type":"string"},"filter_type":{"type":"string"},"is_filterable":{"type":"boolean"},"category_id":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Field definition created"},"400":{"description":"Validation error"},"409":{"description":"field_key already exists for this location"}}}},"/field-definitions/{id}":{"put":{"summary":"Update field definition","description":"Update an existing field definition by ID.","tags":["FieldDefinitions"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"field_label":{"type":"string"},"field_type":{"type":"string"},"filter_type":{"type":"string"},"is_filterable":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Field definition updated"},"400":{"description":"Validation error"},"404":{"description":"Field definition not found or not owned by this location"}}},"delete":{"summary":"Delete field definition","description":"Delete a field definition by ID.","tags":["FieldDefinitions"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Field definition deleted"},"404":{"description":"Not found or not owned by this location"}}}},"/follow-up/scenarios":{"get":{"summary":"List follow-up scenarios for a chatbot","description":"Returns all scenarios with their nodes. Chatbot must belong to this API key's location.","tags":["FollowUp"],"security":[{"followUpReadKeyAuth":[]}],"parameters":[{"in":"query","name":"chatbot_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Array of scenarios with nodes"},"400":{"description":"Missing or invalid chatbot_id"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Chatbot not found or cross-location"}}},"post":{"summary":"Create a follow-up scenario","description":"Creates a new scenario linked to a label. Requires follow_up_automation feature.","tags":["FollowUp"],"security":[{"followUpWriteKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chatbot_id","label_id","name"],"properties":{"chatbot_id":{"type":"string","format":"uuid"},"label_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"skip_if_has_order":{"type":"boolean","default":true},"skip_if_has_phone":{"type":"boolean","default":true},"skip_if_customer_replies":{"type":"boolean","default":true},"skip_labels":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Scenario created"},"400":{"description":"Validation error or duplicate label"},"402":{"description":"follow_up_automation not in plan"}}}},"/follow-up/scenarios/{id}":{"get":{"summary":"Get a single follow-up scenario","tags":["FollowUp"],"security":[{"followUpReadKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"chatbot_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Scenario with nodes"},"404":{"description":"Scenario or chatbot not found"}}},"put":{"summary":"Update a follow-up scenario","tags":["FollowUp"],"security":[{"followUpWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"chatbot_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Updated scenario"},"402":{"description":"follow_up_automation not in plan"},"404":{"description":"Scenario not found"}}},"delete":{"summary":"Delete a follow-up scenario","tags":["FollowUp"],"security":[{"followUpWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"chatbot_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"},"402":{"description":"follow_up_automation not in plan"}}}},"/follow-up/ai-config/{labelId}":{"get":{"summary":"Get AI follow-up config for a label","description":"Returns AI config and milestones. Label must belong to this API key's location.","tags":["FollowUp"],"security":[{"followUpReadKeyAuth":[]}],"parameters":[{"in":"path","name":"labelId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"AI config or null"},"404":{"description":"Label not found or cross-location"}}},"delete":{"summary":"Delete AI follow-up config","description":"Removes AI config and cascades milestones. Requires follow_up_automation feature.","tags":["FollowUp"],"security":[{"followUpWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"labelId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"},"402":{"description":"follow_up_automation not in plan"}}}},"/follow-up/ai-config":{"post":{"summary":"Create or update AI follow-up config","description":"Upserts AI config for a label. Requires follow_up_automation feature.","tags":["FollowUp"],"security":[{"followUpWriteKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label_id"],"properties":{"label_id":{"type":"string","format":"uuid"},"chatbot_id":{"type":"string","format":"uuid"},"enabled":{"type":"boolean","default":false},"global_instruction":{"type":"string"}}}}}},"responses":{"200":{"description":"AI config upserted"},"402":{"description":"follow_up_automation not in plan"},"404":{"description":"Label not found"}}}},"/labels":{"get":{"summary":"List labels for a chatbot","description":"Returns all customer labels attached to the specified chatbot. Chatbot must belong to this API key's location.","tags":["Labels"],"security":[{"labelsReadKeyAuth":[]}],"parameters":[{"in":"query","name":"chatbot_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Array of labels"},"400":{"description":"Missing or invalid chatbot_id"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Chatbot not found or cross-location"}}},"post":{"summary":"Create a label","description":"Creates a new customer label for a chatbot. Max 10 labels per chatbot. Requires follow_up_automation feature.","tags":["Labels"],"security":[{"labelsWriteKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chatbot_id","name"],"properties":{"chatbot_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"color":{"type":"string","description":"Hex color, default #8b5cf6"},"stop_follow_up":{"type":"boolean","default":false}}}}}},"responses":{"201":{"description":"Label created"},"400":{"description":"Validation error or label limit reached"},"401":{"description":"Missing or invalid API key"},"402":{"description":"follow_up_automation not in plan"},"404":{"description":"Chatbot not found or cross-location"}}}},"/labels/{id}":{"put":{"summary":"Update a label","description":"Updates label properties. chatbot_id query param required to enforce ownership. Requires follow_up_automation feature.","tags":["Labels"],"security":[{"labelsWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"chatbot_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Updated label"},"401":{"description":"Missing or invalid API key"},"402":{"description":"follow_up_automation not in plan"},"404":{"description":"Label or chatbot not found"}}},"delete":{"summary":"Delete a label","description":"Deletes label and cascades to assignments/scenarios. chatbot_id query param required. Requires follow_up_automation feature.","tags":["Labels"],"security":[{"labelsWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"chatbot_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"},"401":{"description":"Missing or invalid API key"},"402":{"description":"follow_up_automation not in plan"},"404":{"description":"Label or chatbot not found"}}}},"/leads/export":{"get":{"summary":"Export leads","description":"Export all leads for this location as a JSON array (up to 1000 records).\nUse chatbot_id and status to narrow scope.\n","tags":["Leads"],"security":[{"leadsReadKeyAuth":[]}],"parameters":[{"in":"query","name":"chatbot_id","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"status","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","default":1000,"maximum":1000}}],"responses":{"200":{"description":"Full lead array for CRM sync","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Lead"}}}}}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"Key lacks leads:read permission"}}}},"/leads":{"get":{"summary":"List leads","description":"List leads for this location with optional filters and pagination.","tags":["Leads"],"security":[{"leadsReadKeyAuth":[]}],"parameters":[{"in":"query","name":"chatbot_id","schema":{"type":"string","format":"uuid"},"description":"Filter to a specific chatbot (must belong to this location)"},{"in":"query","name":"status","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"offset","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Paginated list of leads","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"leads":{"type":"array","items":{"$ref":"#/components/schemas/Lead"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}}}}},"/leads/{id}":{"get":{"summary":"Get lead","description":"Get a single lead by ID.","tags":["Leads"],"security":[{"leadsReadKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Lead details","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Lead"}}}}}},"404":{"description":"Lead not found"}}},"patch":{"summary":"Update lead","description":"Update lead status, qualification, or custom_fields. custom_fields are merged (patch semantics).","tags":["Leads"],"security":[{"leadsWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"qualification":{"type":"string"},"custom_fields":{"type":"object"}}}}}},"responses":{"200":{"description":"Lead updated"},"404":{"description":"Lead not found"}}}},"/orders":{"get":{"summary":"List orders","description":"List orders for this location with optional filters and pagination.","tags":["Orders"],"security":[{"ordersReadKeyAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["pending","confirmed","processing","shipped","delivered","returned","cancelled","merged"]}},{"in":"query","name":"payment_status","schema":{"type":"string"}},{"in":"query","name":"chatbot_id","schema":{"type":"string","format":"uuid"},"description":"Filter to a specific chatbot (must belong to this location)"},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"offset","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Paginated list of orders","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"Key lacks orders:read permission"}}},"post":{"summary":"Create order (headless)","description":"Create an order scoped to this location. chatbot_id is optional —\nif omitted the first available chatbot is used internally for FK linking.\n","tags":["Orders"],"security":[{"ordersWriteKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items","customer_phone","customer_address"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderItemInput"}},"customer_name":{"type":"string"},"customer_phone":{"type":"string"},"customer_address":{"type":"string"},"customer_note":{"type":"string"},"shipping_fee":{"type":"number"},"discount":{"type":"number"},"payment_method":{"type":"string"},"chatbot_id":{"type":"string","format":"uuid","description":"Optional — link to a specific chatbot in this location"}}}}}},"responses":{"201":{"description":"Order created"},"400":{"description":"Validation error"}}}},"/orders/{id}":{"get":{"summary":"Get order","description":"Get a single order by ID.","tags":["Orders"],"security":[{"ordersReadKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Order details","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Order"}}}}}},"404":{"description":"Order not found"}}},"patch":{"summary":"Update order","description":"Update allowed order fields (shipping_method, payment_status, shipping_fee, discount, shipping_address).","tags":["Orders"],"security":[{"ordersWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"shipping_method":{"type":"string"},"payment_status":{"type":"string"},"shipping_fee":{"type":"number"},"discount":{"type":"number"},"shipping_address":{"type":"object"}}}}}},"responses":{"200":{"description":"Order updated"},"404":{"description":"Order not found"}}}},"/orders/{id}/status":{"patch":{"summary":"Update order status","description":"Transition an order to a new status.","tags":["Orders"],"security":[{"ordersWriteKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["pending","confirmed","processing","shipped","delivered","returned","cancelled"]}}}}}},"responses":{"200":{"description":"Status updated"},"400":{"description":"Invalid status"},"404":{"description":"Order not found"}}}},"/products":{"post":{"summary":"Create a product","description":"Create a new product with optional variants.\nIf no variants provided, a default variant is auto-created.\n","tags":["Products"],"security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"page_description":{"type":"string"},"product_type":{"type":"string","enum":["physical","digital","service"],"default":"physical"},"status":{"type":"string","enum":["active","draft","archived"],"default":"draft"},"images":{"type":"array","items":{"type":"string"}},"category_id":{"type":"string","format":"uuid"},"unit":{"type":"string"},"variants":{"type":"array","items":{"$ref":"#/components/schemas/VariantInput"}}}}}}},"responses":{"201":{"description":"Product created with variants"},"400":{"description":"Invalid input"}}},"get":{"summary":"List products","description":"List products with pagination, search, and status filter","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["active","draft","archived"]},"description":"Filter by product status"},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search by product name"},{"in":"query","name":"category_id","schema":{"type":"string","format":"uuid"},"description":"Filter by category"},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100},"description":"Number of results per page"},{"in":"query","name":"offset","schema":{"type":"integer","default":0},"description":"Number of results to skip"}],"responses":{"200":{"description":"List of products"},"401":{"description":"Invalid or missing API key"},"403":{"description":"API key lacks 'products' permission"}}}},"/products/{id}":{"get":{"summary":"Get product details","description":"Get a single product with all variants","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Product ID"}],"responses":{"200":{"description":"Product details with variants"},"404":{"description":"Product not found"}}},"delete":{"summary":"Delete a product","description":"Delete a product and all its variants","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product deleted"},"404":{"description":"Product not found"}}},"put":{"summary":"Update a product","description":"Update product fields (not variants - use variant endpoints)","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"page_description":{"type":"string"},"product_type":{"type":"string","enum":["physical","digital","service"]},"status":{"type":"string","enum":["active","draft","archived"]},"images":{"type":"array","items":{"type":"string"}},"category_id":{"type":"string","format":"uuid"},"unit":{"type":"string"}}}}}},"responses":{"200":{"description":"Product updated"},"404":{"description":"Product not found"}}}},"/products/bulk-delete":{"post":{"summary":"Bulk delete products","description":"Delete multiple products at once (max 100)","tags":["Products"],"security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":100}}}}}},"responses":{"200":{"description":"Bulk delete result"}}}},"/products/variants/{sku}/inventory":{"post":{"summary":"Update inventory by SKU","description":"Adjust quantity for a variant by SKU (positive to add, negative to subtract)","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"path","name":"sku","required":true,"schema":{"type":"string"},"description":"Variant SKU"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["change"],"properties":{"change":{"type":"integer","description":"Quantity change (positive=add, negative=subtract)"}}}}}},"responses":{"200":{"description":"Inventory updated"},"400":{"description":"Invalid change value"},"404":{"description":"Variant not found"}}}},"/products/{id}/variants":{"get":{"summary":"List variants for a product","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Product ID"}],"responses":{"200":{"description":"List of variants"},"404":{"description":"Product not found"}}},"post":{"summary":"Create a variant","description":"Add a new variant to a product","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Product ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VariantInput"}}}},"responses":{"201":{"description":"Variant created"},"404":{"description":"Product not found"}}}},"/products/variants/{id}":{"put":{"summary":"Update a variant","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Variant ID"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"sku":{"type":"string"},"price":{"type":"number"},"compare_at_price":{"type":"number"},"currency":{"type":"string"},"quantity":{"type":"integer"},"track_inventory":{"type":"boolean"},"allow_oversell":{"type":"boolean"},"is_active":{"type":"boolean"},"image_url":{"type":"string"}}}}}},"responses":{"200":{"description":"Variant updated"},"404":{"description":"Variant not found"}}},"delete":{"summary":"Delete a variant","tags":["Products"],"security":[{"apiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Variant ID"}],"responses":{"200":{"description":"Variant deleted"},"404":{"description":"Variant not found"}}}},"/webhooks":{"get":{"summary":"List webhooks","description":"List all outgoing webhooks for a chatbot (scoped to this location).","tags":["Webhooks"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"query","name":"chatbot_id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Chatbot ID (must belong to this location)"}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"400":{"description":"Missing or invalid chatbot_id"},"403":{"description":"Chatbot not owned by this location"}}},"post":{"summary":"Create webhook","description":"Create a custom outgoing webhook for a chatbot. Only custom (HTTPS) webhooks\nare supported via REST. Meta CAPI webhooks require the MCP interface for\nfull pixel validation.\n","tags":["Webhooks"],"security":[{"chatbotApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chatbot_id","name","url"],"properties":{"chatbot_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"url":{"type":"string","format":"uri","description":"Must be HTTPS"},"events":{"type":"array","items":{"type":"string","enum":["label_assigned","order_created","order_updated","order_cancelled","lead_captured","conversation_transferred"]},"default":["label_assigned"]},"generate_secret":{"type":"boolean","description":"Generate HMAC signing secret (returned once, store it)"}}}}}},"responses":{"201":{"description":"Webhook created. If generate_secret=true, secret is returned only once."},"400":{"description":"Validation error"},"403":{"description":"Chatbot not owned by this location"}}}},"/webhooks/{id}":{"put":{"summary":"Update webhook","description":"Update webhook name, URL, events, or active state.","tags":["Webhooks"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Webhook updated"},"403":{"description":"Webhook not owned by this location"},"404":{"description":"Webhook not found"}}},"delete":{"summary":"Delete webhook","description":"Delete a webhook configuration.","tags":["Webhooks"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Webhook deleted"},"403":{"description":"Webhook not found or not owned by this location"}}}},"/webhooks/{id}/logs":{"get":{"summary":"Get webhook logs","description":"List recent execution logs for a webhook (excludes test runs by default).","tags":["Webhooks"],"security":[{"chatbotApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"status","schema":{"type":"string","enum":["success","failed","pending"]}},{"in":"query","name":"limit","schema":{"type":"integer","default":50,"maximum":100}},{"in":"query","name":"offset","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Webhook execution logs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookLog"}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}}}}}},"x-brand":{"name":"Mooly","isWhitelabel":true}}