{
  "openapi": "3.0.3",
  "info": {
    "title": "Elaras Chat API",
    "version": "1.0.0",
    "description": "REST API for Elaras Chat.\n\n**Public endpoints** use `X-Chatbot-Key: cbt_...` + `X-Elaras-Fingerprint: <hash>` headers.\n\n**Developer endpoints** use `Authorization: Bearer sk_...` and live under `/api/developer/v1/`."
  },
  "servers": [
    {
      "url": "https://api.elaras.ai/api",
      "description": "Production"
    }
  ],
  "components": {
    "securitySchemes": {
      "ChatbotKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Chatbot-Key",
        "description": "Public chatbot key (`cbt_...`). Required for all public chat endpoints."
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Team secret key (`sk_...`). Required for all developer endpoints."
      }
    },
    "parameters": {
      "ChatbotId": {
        "name": "chatbot_id",
        "in": "path",
        "required": true,
        "schema": { "type": "string" },
        "description": "The chatbot's public key (`cbt_...`)."
      },
      "Fingerprint": {
        "name": "X-Elaras-Fingerprint",
        "in": "header",
        "required": false,
        "schema": { "type": "string", "maxLength": 128 },
        "description": "Browser fingerprint hash. Sent automatically by the widget and SDK. Used in rate-limit keying and stored on the session for fraud visibility."
      }
    },
    "schemas": {
      "ChatMessage": {
        "type": "object",
        "properties": {
          "id":         { "type": "integer", "example": 42 },
          "role":       { "type": "string", "enum": ["user", "assistant"], "example": "assistant" },
          "content":    { "type": "string", "example": "Hello! How can I help you today?" },
          "created_at": { "type": "string", "format": "date-time", "example": "2026-07-24T10:30:00Z" }
        },
        "required": ["id", "role", "content", "created_at"]
      },
      "SessionData": {
        "type": "object",
        "properties": {
          "session":  { "type": "string", "format": "uuid", "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" },
          "messages": { "type": "array", "items": { "$ref": "#/components/schemas/ChatMessage" } }
        },
        "required": ["session", "messages"]
      },
      "ChatbotConfig": {
        "type": "object",
        "properties": {
          "id":               { "type": "string", "example": "cbt_abc123" },
          "name":             { "type": "string", "example": "Support Bot" },
          "greeting_message": { "type": "string", "nullable": true, "example": "Hi! How can I help?" },
          "avatar_url":       { "type": "string", "nullable": true, "example": "https://cdn.elaras.ai/avatars/bot.png" },
          "collect_leads":    { "type": "boolean", "example": false },
          "lead_prompt":      { "type": "string", "nullable": true, "example": "Before we continue, can I grab your email?" },
          "triage_questions": {
            "nullable": true,
            "type": "object",
            "properties": {
              "ask_name":  { "type": "object", "properties": { "enabled": { "type": "boolean" }, "question": { "type": "string" } } },
              "ask_email": { "type": "object", "properties": { "enabled": { "type": "boolean" }, "question": { "type": "string" } } },
              "custom":    { "type": "array", "items": { "type": "object", "properties": { "question": { "type": "string" } } } }
            }
          },
          "appearance": {
            "nullable": true,
            "type": "object",
            "properties": {
              "primary_color": { "type": "string", "example": "#7c3aed" },
              "position":      { "type": "string", "enum": ["bottom-right", "bottom-left"], "example": "bottom-right" },
              "bubble_text":   { "type": "string", "nullable": true, "example": "Chat with us" },
              "powered_by":    { "type": "boolean", "example": true },
              "bubble_icon":   { "type": "string", "enum": ["default", "avatar"], "example": "default" },
              "theme":         { "type": "string", "enum": ["light", "dark", "auto"], "example": "light" }
            }
          },
          "reverb": {
            "type": "object",
            "properties": {
              "key":    { "type": "string", "example": "elaras-chat" },
              "host":   { "type": "string", "example": "ws.elaras.ai" },
              "port":   { "type": "integer", "example": 6001 },
              "scheme": { "type": "string", "enum": ["ws", "wss"], "example": "wss" }
            }
          }
        },
        "required": ["id", "name", "collect_leads", "reverb"]
      },
      "StartSessionResponse": {
        "type": "object",
        "properties": {
          "session_token": { "type": "string", "format": "uuid", "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" },
          "messages":      { "type": "array", "items": { "$ref": "#/components/schemas/ChatMessage" } }
        },
        "required": ["session_token", "messages"]
      },
      "TriageAnswer": {
        "type": "object",
        "properties": {
          "type":     { "type": "string", "enum": ["name", "email", "custom"], "example": "email" },
          "question": { "type": "string", "example": "What is your email address?" },
          "answer":   { "type": "string", "example": "user@example.com" }
        },
        "required": ["type", "question", "answer"]
      },
      "Skill": {
        "type": "object",
        "properties": {
          "id":          { "type": "integer", "example": 1 },
          "name":        { "type": "string", "example": "get_order_status" },
          "description": { "type": "string", "example": "Look up a customer's order status by order number." },
          "url":         { "type": "string", "format": "uri", "example": "https://yoursite.com/api/elaras/order-status" },
          "parameters":  { "type": "object", "description": "JSON Schema object describing the parameters the AI extracts." },
          "enabled":     { "type": "boolean", "example": true }
        },
        "required": ["id", "name", "description", "url", "enabled"]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id":     { "type": "integer", "example": 1 },
          "url":    { "type": "string", "format": "uri", "example": "https://yoursite.com/api/elaras/webhook" },
          "events": { "type": "array", "items": { "type": "string" }, "example": ["message.created", "lead.captured"] },
          "active": { "type": "boolean", "example": true }
        },
        "required": ["id", "url", "events", "active"]
      },
      "Error": {
        "type": "object",
        "properties": {
          "message": { "type": "string", "example": "Invalid chatbot key." }
        },
        "required": ["message"]
      },
      "OkResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": true }
        }
      }
    }
  },
  "paths": {
    "/v1/chat/{chatbot_id}/config": {
      "get": {
        "operationId": "getChatbotConfig",
        "summary": "Get chatbot config",
        "description": "Returns the chatbot's public configuration — name, greeting, appearance, lead capture settings, triage questions, and Reverb WebSocket connection details. Call this once on page load to initialise the widget.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/ChatbotId" },
          { "$ref": "#/components/parameters/Fingerprint" }
        ],
        "responses": {
          "200": {
            "description": "Chatbot configuration.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatbotConfig" } } }
          },
          "401": {
            "description": "Invalid chatbot key.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/v1/chat/{chatbot_id}/start": {
      "post": {
        "operationId": "startSession",
        "summary": "Start or resume a session",
        "description": "Creates a new session or resumes an existing one. Returns any messages already in the session (e.g. greeting messages from a previous visit). Call this when the chat panel first opens.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/ChatbotId" },
          { "$ref": "#/components/parameters/Fingerprint" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["session_token"],
                "properties": {
                  "session_token": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Client-generated UUID. Generate once and persist in localStorage.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session started. Contains any existing messages.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StartSessionResponse" } } }
          },
          "401": {
            "description": "Invalid chatbot key.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/v1/chat/{chatbot_id}/send": {
      "post": {
        "operationId": "sendMessage",
        "summary": "Send a message (async / streaming)",
        "description": "Queues a message for AI processing. The response is delivered via WebSocket to the `chat.{session_token}` Reverb channel as `chat.token` events followed by a `chat.done` event. Use this when you have an active WebSocket connection.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/ChatbotId" },
          { "$ref": "#/components/parameters/Fingerprint" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["session_token", "message"],
                "properties": {
                  "session_token": { "type": "string", "format": "uuid", "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" },
                  "message":       { "type": "string", "example": "What are your opening hours?" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message queued. Response delivered via WebSocket.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } }
          },
          "401": { "description": "Invalid chatbot key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "422": { "description": "Validation error or no credits.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/v1/chat/{chatbot_id}/complete": {
      "post": {
        "operationId": "completeMessage",
        "summary": "Send a message (synchronous)",
        "description": "Sends a message and waits for the full AI response synchronously. No WebSocket required. Good for server-side integrations or simple non-streaming UIs.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/ChatbotId" },
          { "$ref": "#/components/parameters/Fingerprint" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["session_token", "message"],
                "properties": {
                  "session_token": { "type": "string", "format": "uuid", "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" },
                  "message":       { "type": "string", "example": "What are your opening hours?" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Full AI response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message_id":   { "type": "integer", "example": 42 },
                    "response":     { "type": "string", "example": "We are open Monday to Friday, 9am–5pm." },
                    "credits_used": { "type": "integer", "example": 4 }
                  },
                  "required": ["message_id", "response", "credits_used"]
                }
              }
            }
          },
          "401": { "description": "Invalid chatbot key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "422": { "description": "Validation error or no credits.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/v1/chat/{chatbot_id}/session/{session_token}": {
      "get": {
        "operationId": "getSession",
        "summary": "Get session history",
        "description": "Returns the session and its full message history. Useful for restoring conversation state on page reload.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/ChatbotId" },
          { "$ref": "#/components/parameters/Fingerprint" },
          { "name": "session_token", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Session with messages. Returns empty messages array if session does not exist.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionData" } } }
          }
        }
      },
      "delete": {
        "operationId": "clearSession",
        "summary": "Clear a session",
        "description": "Deletes the session and all its messages. The conversation starts fresh on the next `/start` call.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/ChatbotId" },
          { "name": "session_token", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Session cleared.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "cleared": { "type": "boolean", "example": true } } } } }
          }
        }
      }
    },
    "/v1/chat/{chatbot_id}/lead": {
      "post": {
        "operationId": "captureLead",
        "summary": "Capture lead info",
        "description": "Associates a name and/or email with the session. Triggers the `lead.captured` webhook event if configured.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ChatbotId" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["session_token", "email"],
                "properties": {
                  "session_token": { "type": "string", "format": "uuid", "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" },
                  "email":         { "type": "string", "format": "email", "example": "user@example.com" },
                  "name":          { "type": "string", "nullable": true, "example": "Jordan" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Lead captured.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } }
        }
      }
    },
    "/v1/chat/{chatbot_id}/triage": {
      "post": {
        "operationId": "submitTriage",
        "summary": "Submit triage answers",
        "description": "Stores pre-chat answers (name, email, custom questions) collected before the conversation starts.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ChatbotId" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["session_token", "answers"],
                "properties": {
                  "session_token": { "type": "string", "format": "uuid" },
                  "answers":       { "type": "array", "items": { "$ref": "#/components/schemas/TriageAnswer" } }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Triage answers stored.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } }
        }
      }
    },
    "/v1/chat/{chatbot_id}/feedback": {
      "post": {
        "operationId": "submitFeedback",
        "summary": "Submit message feedback",
        "description": "Records a thumbs-up or thumbs-down rating against an AI response message.",
        "tags": ["Public Chat"],
        "security": [{ "ChatbotKey": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ChatbotId" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["message_id", "rating"],
                "properties": {
                  "message_id": { "type": "integer", "example": 42 },
                  "rating":     { "type": "string", "enum": ["up", "down"], "example": "up" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Feedback recorded.", "content": { "application/json": { "schema": { "type": "object", "properties": { "recorded": { "type": "boolean", "example": true } } } } } }
        }
      }
    },
    "/developer/v1/sessions": {
      "get": {
        "operationId": "listSessions",
        "summary": "List sessions",
        "description": "Returns a paginated list of all sessions across all chatbots for the authenticated team.",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "page",     "in": "query", "schema": { "type": "integer", "default": 1 } },
          { "name": "per_page", "in": "query", "schema": { "type": "integer", "default": 15, "maximum": 100 } }
        ],
        "responses": {
          "200": {
            "description": "Paginated sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data":         { "type": "array", "items": { "$ref": "#/components/schemas/SessionData" } },
                    "total":        { "type": "integer", "example": 120 },
                    "per_page":     { "type": "integer", "example": 15 },
                    "current_page": { "type": "integer", "example": 1 }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid Bearer token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/developer/v1/sessions/{session_id}": {
      "get": {
        "operationId": "getDeveloperSession",
        "summary": "Get a session",
        "description": "Returns a single session with its full message history.",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "session_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": { "description": "Session with messages.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionData" } } } },
          "404": { "description": "Session not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/developer/v1/sessions/{session_id}/messages": {
      "post": {
        "operationId": "sendDeveloperMessage",
        "summary": "Send a message (server-side)",
        "description": "Sends a message to a session from your server. The AI response is delivered via WebSocket to the session channel — it is NOT in the HTTP response body. If the session does not exist yet, `chatbot_key` is required to create it.",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "session_id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["message"],
                "properties": {
                  "message":     { "type": "string", "example": "Hello, how can I help you today?" },
                  "chatbot_key": { "type": "string", "description": "Required if the session does not exist yet.", "example": "cbt_abc123" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Message queued.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } },
          "401": { "description": "Invalid Bearer token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "422": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/developer/v1/chatbots": {
      "get": {
        "operationId": "listChatbots",
        "summary": "List chatbots",
        "description": "Returns all chatbots belonging to the authenticated team.",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "200": {
            "description": "List of chatbots.",
            "content": {
              "application/json": {
                "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ChatbotConfig" } }
              }
            }
          },
          "401": { "description": "Invalid Bearer token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/developer/v1/chatbots/{chatbot_id}/skills": {
      "get": {
        "operationId": "listSkills",
        "summary": "List skills",
        "description": "Returns all skills configured for a chatbot.",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "chatbot_id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "The chatbot's public key or internal ID." }
        ],
        "responses": {
          "200": { "description": "List of skills.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Skill" } } } } },
          "401": { "description": "Invalid Bearer token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      },
      "post": {
        "operationId": "createSkill",
        "summary": "Create a skill",
        "description": "Adds a new skill to a chatbot. The AI will call this skill's endpoint when it decides the skill is relevant.",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "chatbot_id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "description", "url"],
                "properties": {
                  "name":        { "type": "string", "example": "get_order_status", "description": "Lowercase snake_case identifier. The AI sees this name." },
                  "description": { "type": "string", "example": "Look up a customer's order status by order number.", "description": "Plain English. The AI reads this to decide when to call the skill." },
                  "url":         { "type": "string", "format": "uri", "example": "https://yoursite.com/api/elaras/order-status" },
                  "parameters":  { "type": "object", "description": "JSON Schema object for the parameters the AI extracts from the conversation." }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Skill created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Skill" } } } },
          "422": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/developer/v1/chatbots/{chatbot_id}/skills/{skill_id}": {
      "put": {
        "operationId": "updateSkill",
        "summary": "Update a skill",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "chatbot_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "skill_id",   "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name":        { "type": "string" },
                  "description": { "type": "string" },
                  "url":         { "type": "string", "format": "uri" },
                  "parameters":  { "type": "object" },
                  "enabled":     { "type": "boolean" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Skill updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Skill" } } } }
        }
      },
      "delete": {
        "operationId": "deleteSkill",
        "summary": "Delete a skill",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "chatbot_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "skill_id",   "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Skill deleted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } }
        }
      }
    },
    "/developer/v1/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List webhooks",
        "description": "Returns all configured webhooks for the authenticated team.",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "200": { "description": "List of webhooks.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Webhook" } } } } }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Create a webhook",
        "description": "Registers a new webhook endpoint to receive events.",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url", "events"],
                "properties": {
                  "url":    { "type": "string", "format": "uri", "example": "https://yoursite.com/api/elaras/webhook" },
                  "events": { "type": "array", "items": { "type": "string" }, "example": ["message.created", "lead.captured"] }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Webhook created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Webhook" } } } }
        }
      }
    },
    "/developer/v1/webhooks/{webhook_id}": {
      "put": {
        "operationId": "updateWebhook",
        "summary": "Update a webhook",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "webhook_id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url":    { "type": "string", "format": "uri" },
                  "events": { "type": "array", "items": { "type": "string" } },
                  "active": { "type": "boolean" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Webhook updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Webhook" } } } }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Delete a webhook",
        "tags": ["Developer API"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          { "name": "webhook_id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Webhook deleted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Public Chat",
      "description": "Widget/SDK endpoints. Authenticated with `X-Chatbot-Key: cbt_...`. Base URL: `/api/v1/chat/{chatbot_id}/`."
    },
    {
      "name": "Developer API",
      "description": "Server-side endpoints for programmatic access. Authenticated with `Authorization: Bearer sk_...`. Base URL: `/api/developer/v1/`."
    }
  ]
}
