{
  "openapi": "3.1.0",
  "info": {
    "title": "Lina API",
    "version": "1.0.0",
    "description": "The Lina API lets software use an organization's Lina: ask it questions, read and add its knowledge, read its calls, send texts to people who agreed to get them, see its usage and be told when things happen.\n\n**Keys.** Make a Lina API key in the Command Center under Settings, API access. A key is shown once, belongs to one organization and carries only the scopes it was given. Send it as `Authorization: Bearer <key>`. Keep it on a server: never in a web page or an app. A key you revoke stops working at once on the server that handled the revoke and within 30 seconds on every other.\n\n**Compatible with OpenAI's clients.** Point the OpenAI SDK's base URL here and use the model `lina`.\n\n**Answers are AI output.** If your software shows an answer to a person, say it came from an AI.\n\n**Limits.** A key may make 60 requests a minute and an organization 120 across its keys; a key may be given a lower number. The counts are kept per server, so treat them as approximate; the headers `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` say where you stand, and a 429 carries `Retry-After`. A request body may be 256 KB. Answers count toward the organization's monthly answers, the same ones its Website chat uses.\n\n**Writes you may send twice.** Send an `Idempotency-Key` (1 to 64 letters, digits and `. _ : -`) and the same request within 24 hours returns the first answer with `Idempotent-Replayed: true`. Chat and answers are not idempotent: a retry is a new answer and is counted again.\n\n**Errors** are always `{\"error\": {\"message\", \"type\", \"code\", \"param\", \"request_id\"}}`. Branch on `code`; quote `request_id` when you write to support."
  },
  "servers": [
    {
      "url": "https://api.linasystems.org/v1",
      "description": "The Lina API"
    }
  ],
  "tags": [
    {
      "name": "Chat",
      "description": "Ask the organization's Lina a question and get an answer from its own knowledge."
    },
    {
      "name": "Knowledge",
      "description": "Read and add the cards the assistants answer from."
    },
    {
      "name": "Calls",
      "description": "Read the calls the phone line answered."
    },
    {
      "name": "Texts",
      "description": "Send a text to a person who agreed to get one."
    },
    {
      "name": "Usage",
      "description": "See what the organization and each key has used this month."
    },
    {
      "name": "Webhooks",
      "description": "Be told when something happens, with ids only."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/chat/completions": {
      "post": {
        "operationId": "createChatCompletion",
        "tags": [
          "Chat"
        ],
        "summary": "Create a chat completion",
        "description": "Ask the organization's Lina a question in the shape OpenAI's chat completions use, so an OpenAI client works with only its base URL and key changed. The answer is the Website chat's answer: from this organization's own knowledge, under the same rules, counted in the same monthly answers.\n\n`model` must be `lina`. A `system` or `developer` message is folded, at most 2,000 characters of them in all, into a labelled block beneath Lina's own rules: it can shape tone and format and cannot outrank them. Parameters Lina owns (`temperature`, `top_p`, `max_tokens`, `max_completion_tokens`, `stop`, `presence_penalty`, `frequency_penalty`, `seed`, `user`) are ignored and named in the `X-Lina-Ignored-Params` response header. Tools, functions, `response_format`, `n` above 1 and `logprobs` are refused with 400 `unsupported_parameter`.\n\nWith `stream: true` the answer is sent as server-sent events in slices of about 96 characters, once it is complete and checked: the first byte arrives when the whole answer is ready, and a client never holds text that is later changed. Ends with `data: [DONE]`.\n\nScope: `chat`.",
        "x-lina-scope": "chat",
        "x-lina-module": null,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              },
              "example": {
                "model": "lina",
                "messages": [
                  {
                    "role": "user",
                    "content": "What time do you open on Saturdays?"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer, or a server-sent event stream when `stream` is true.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Lina-Ignored-Params": {
                "$ref": "#/components/headers/X-Lina-Ignored-Params"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletion"
                },
                "example": {
                  "id": "chatcmpl-0123456789abcdef01234567",
                  "object": "chat.completion",
                  "created": 1793232000,
                  "model": "lina",
                  "choices": [
                    {
                      "index": 0,
                      "message": {
                        "role": "assistant",
                        "content": "We open at 9 a.m. on Saturdays."
                      },
                      "finish_reason": "stop"
                    }
                  ],
                  "usage": {
                    "prompt_tokens": 412,
                    "completion_tokens": 38,
                    "total_tokens": 450
                  }
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                },
                "example": "data: {\"id\":\"chatcmpl-0123456789abcdef01234567\",\"object\":\"chat.completion.chunk\",\"created\":1793232000,\"model\":\"lina\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"We open at 9 \"},\"finish_reason\":null}]}\n\ndata: [DONE]\n\n"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "413": {
            "$ref": "#/components/responses/Error413"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/answers": {
      "post": {
        "operationId": "createAnswer",
        "tags": [
          "Chat"
        ],
        "summary": "Ask one question",
        "description": "A question in, an answer out, with no conversation. `context` is background from your software, folded in the way a system message of the chat endpoint is. Counted like a chat answer, and like it, not idempotent: a retry is a new answer.\n\nScope: `chat`.",
        "x-lina-scope": "chat",
        "x-lina-module": null,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnswerRequest"
              },
              "example": {
                "question": "Do you take walk-ins?",
                "context": "Answer in one sentence."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Lina-Ignored-Params": {
                "$ref": "#/components/headers/X-Lina-Ignored-Params"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Answer"
                },
                "example": {
                  "id": "ans_0123456789abcdef01234567",
                  "object": "answer",
                  "answer": "Yes, walk-ins are welcome.",
                  "usage": {
                    "prompt_tokens": 412,
                    "completion_tokens": 38,
                    "total_tokens": 450
                  },
                  "model": "lina"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "413": {
            "$ref": "#/components/responses/Error413"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/models": {
      "get": {
        "operationId": "listModels",
        "tags": [
          "Chat"
        ],
        "summary": "List models",
        "description": "Lina serves one model, `lina`. It is not a switch: which AI answers is the organization's and the platform's choice, and no answer names it.\n\nScope: `chat`.",
        "x-lina-scope": "chat",
        "x-lina-module": null,
        "responses": {
          "200": {
            "description": "The model list.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "lina",
                      "object": "model",
                      "created": 1793232000,
                      "owned_by": "lina"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/knowledge": {
      "get": {
        "operationId": "listKnowledge",
        "tags": [
          "Knowledge"
        ],
        "summary": "List knowledge cards",
        "description": "The cards the assistants answer from, newest first, or best match first with `q`. The organization's private notes are never listed. 403 `knowledge_read_disabled` when the organization has switched reading knowledge from outside off.\n\nScope: `knowledge:read`. The organization's plan must include the `knowledge` module.",
        "x-lina-scope": "knowledge:read",
        "x-lina-module": "knowledge",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20
            },
            "description": "How many to return, 1 to 100. Default 20."
          },
          {
            "name": "starting_after",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 64
                },
                {
                  "type": "null"
                }
              ]
            },
            "description": "The id of the last item of the previous page. Pages follow it in order."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "null"
                }
              ]
            },
            "description": "Search words. Best match first."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of cards.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "ku_3fa81c2b9d",
                      "object": "knowledge",
                      "title": "Saturday hours",
                      "body": "We are open Saturdays from 9 a.m. to 1 p.m.",
                      "source": "api:key_000000000001",
                      "tags": [
                        "api",
                        "hours"
                      ],
                      "created_at": "2026-10-29T17:02:11Z"
                    }
                  ],
                  "has_more": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      },
      "post": {
        "operationId": "createKnowledge",
        "tags": [
          "Knowledge"
        ],
        "summary": "Add a knowledge card",
        "description": "Adds a fact the assistants can use, through the same writer the Command Center uses. A card may not carry a standing order for the assistants (a line starting `DIRECTIVE:`, `ALWAYS:`, `NEVER:` or `PIN:`), a line that sets a fact they keep, or a reserved tag: those stay a person's decision. An organization may hold 500 cards written through the API and write 1,000 a day (cards deleted today count). Repeating a card with the same title and body saves nothing new.\n\nScope: `knowledge:write`. The organization's plan must include the `knowledge` module.",
        "x-lina-scope": "knowledge:write",
        "x-lina-module": "knowledge",
        "parameters": [
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KnowledgeInput"
              },
              "example": {
                "title": "Saturday hours",
                "body": "We are open Saturdays from 9 a.m. to 1 p.m.",
                "tags": [
                  "hours"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The card.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeCard"
                },
                "example": {
                  "id": "ku_3fa81c2b9d",
                  "object": "knowledge",
                  "title": "Saturday hours",
                  "body": "We are open Saturdays from 9 a.m. to 1 p.m.",
                  "source": "api:key_000000000001",
                  "tags": [
                    "api",
                    "hours"
                  ],
                  "created_at": "2026-10-29T17:02:11Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "413": {
            "$ref": "#/components/responses/Error413"
          },
          "422": {
            "$ref": "#/components/responses/Error422"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/knowledge/{knowledge_id}": {
      "delete": {
        "operationId": "deleteKnowledge",
        "tags": [
          "Knowledge"
        ],
        "summary": "Delete a knowledge card",
        "description": "Takes a card the API added out of what the assistants say, at once. A person can still bring the card back from Deleted answers in the Command Center for 30 days. A card written in the Command Center cannot be deleted here (403 `reserved_row`).\n\nScope: `knowledge:write`. The organization's plan must include the `knowledge` module.",
        "x-lina-scope": "knowledge:write",
        "x-lina-module": "knowledge",
        "parameters": [
          {
            "name": "knowledge_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The card's id."
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "responses": {
          "200": {
            "description": "The card is deleted.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                },
                "example": {
                  "id": "ku_3fa81c2b9d",
                  "object": "knowledge",
                  "deleted": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/calls": {
      "get": {
        "operationId": "listCalls",
        "tags": [
          "Calls"
        ],
        "summary": "List calls",
        "description": "The calls the phone line answered, newest first. Never the audio, a payment or a cost; a call that took a payment shows no summary.\n\nScope: `calls:read`. The organization's plan must include the `phone` module.",
        "x-lina-scope": "calls:read",
        "x-lina-module": "phone",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20
            },
            "description": "How many to return, 1 to 100. Default 20."
          },
          {
            "name": "starting_after",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 64
                },
                {
                  "type": "null"
                }
              ]
            },
            "description": "The id of the last item of the previous page. Pages follow it in order."
          },
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 64
                },
                {
                  "type": "null"
                }
              ]
            },
            "description": "Only calls with this tag."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 64
                },
                {
                  "type": "null"
                }
              ]
            },
            "description": "Only calls with this status."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of calls.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "CA0000000000000000000000000000000a",
                      "object": "call",
                      "started_at": "2026-10-29T16:40:02Z",
                      "ended_at": "2026-10-29T16:42:31Z",
                      "duration_seconds": 149,
                      "caller_number": "+16195550101",
                      "status": "completed",
                      "tag": "booking",
                      "resolved": true,
                      "callback_needed": false,
                      "callback_done": false,
                      "voicemail": false,
                      "escalated": false,
                      "summary": "The caller asked about Saturday hours and was told 9 to 1.",
                      "summary_redacted": false
                    }
                  ],
                  "has_more": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/calls/{call_id}": {
      "get": {
        "operationId": "getCall",
        "tags": [
          "Calls"
        ],
        "summary": "Get a call",
        "description": "One call. The transcript is included only for a key with the `calls:transcripts` scope, because it is the caller's own speech.\n\nScope: `calls:read`. The organization's plan must include the `phone` module.",
        "x-lina-scope": "calls:read",
        "x-lina-module": "phone",
        "parameters": [
          {
            "name": "call_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The call's id."
          }
        ],
        "responses": {
          "200": {
            "description": "The call.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Call"
                },
                "example": {
                  "id": "CA0000000000000000000000000000000a",
                  "object": "call",
                  "started_at": "2026-10-29T16:40:02Z",
                  "ended_at": "2026-10-29T16:42:31Z",
                  "duration_seconds": 149,
                  "caller_number": "+16195550101",
                  "status": "completed",
                  "tag": "booking",
                  "resolved": true,
                  "callback_needed": false,
                  "callback_done": false,
                  "voicemail": false,
                  "escalated": false,
                  "summary": "The caller asked about Saturday hours and was told 9 to 1.",
                  "summary_redacted": false,
                  "callback_number": null,
                  "transcript_redacted": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/texts": {
      "post": {
        "operationId": "sendText",
        "tags": [
          "Texts"
        ],
        "summary": "Send a text",
        "description": "Sends one text from the organization's own number, through the same checks as the Command Center: the person must have agreed to get texts (there is no way to record that agreement through the API), quiet hours, opt-outs and credits all apply. The Idempotency-Key also stops a second text going out if you send the request twice. A 502 with the code `failed_unknown` or `twilio_unknown` means the text may have gone out: do not send it again.\n\nScope: `texts:send`. The organization's plan must include the `outbound` module.",
        "x-lina-scope": "texts:send",
        "x-lina-module": "outbound",
        "parameters": [
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TextRequest"
              },
              "example": {
                "to": "+16195550101",
                "body": "Your appointment is tomorrow at 10."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The text was sent (200 for a repeat of the same Idempotency-Key).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Text"
                },
                "example": {
                  "id": "SM0000000000000000000000000000000a",
                  "object": "text",
                  "status": "sent",
                  "segments": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "413": {
            "$ref": "#/components/responses/Error413"
          },
          "422": {
            "$ref": "#/components/responses/Error422"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "operationId": "getUsage",
        "tags": [
          "Usage"
        ],
        "summary": "Get this month's usage",
        "description": "The organization's allowances this month (AI answers, web-search lookups, and phone minutes or answered calls where the plan has them) and what each key answered. Never a cost.\n\nScope: `usage:read`.",
        "x-lina-scope": "usage:read",
        "x-lina-module": null,
        "responses": {
          "200": {
            "description": "The usage.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageReport"
                },
                "example": {
                  "object": "usage",
                  "plan": {
                    "key": "pro",
                    "name": "Pro"
                  },
                  "month": "2026-10",
                  "resets_at": "2026-11-01T00:00:00+00:00",
                  "ledger_readable": true,
                  "allowances": [
                    {
                      "key": "ai_answers",
                      "label": "AI answers",
                      "used": 212,
                      "limit": 3000,
                      "percent": 7,
                      "reached": false
                    }
                  ],
                  "today": {
                    "answers": 14
                  },
                  "api": {
                    "answers_this_month": 96,
                    "answers_today": 9,
                    "keys": [
                      {
                        "key_id": "key_000000000001",
                        "label": "Billing sync",
                        "status": "active",
                        "answers_this_month": 96,
                        "answers_today": 9,
                        "monthly_answer_cap": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhooks",
        "description": "The webhooks made through this API. Each is sent a thin event: what happened and the ids involved, never a name, number or message. See the `lina.event` webhook below for the body and the `X-Lina-Signature` signature. Nothing is sent while the organization has delivery to partner systems switched off (`delivery_enabled`).\n\nScope: `webhooks:manage`.",
        "x-lina-scope": "webhooks:manage",
        "x-lina-module": null,
        "responses": {
          "200": {
            "description": "The webhooks.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "5d9a3c01e7b2",
                      "object": "webhook",
                      "url": "https://example.org/hooks/lina",
                      "events": [
                        "call.received",
                        "knowledge.updated"
                      ],
                      "format": "v1",
                      "created_at": "2026-10-29T17:05:00Z"
                    }
                  ],
                  "delivery_enabled": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Add a webhook",
        "description": "Subscribes a public address to events: `chat.handoff_requested`, `call.received`, `call.escalated`, `text.received`, `form.submitted`, `email.received`, `knowledge.updated`, `usage.allowance_reached`, or `*` for all of them. The signing secret is in this answer and nowhere else. An organization may hold 10 webhooks made through the API.\n\nScope: `webhooks:manage`.",
        "x-lina-scope": "webhooks:manage",
        "x-lina-module": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookInput"
              },
              "example": {
                "url": "https://example.org/hooks/lina",
                "events": [
                  "call.received"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The webhook, with its signing secret.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                },
                "example": {
                  "id": "5d9a3c01e7b2",
                  "object": "webhook",
                  "url": "https://example.org/hooks/lina",
                  "events": [
                    "call.received",
                    "knowledge.updated"
                  ],
                  "format": "v1",
                  "created_at": "2026-10-29T17:05:00Z",
                  "secret": "(shown once)"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "413": {
            "$ref": "#/components/responses/Error413"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/webhooks/{webhook_id}": {
      "delete": {
        "operationId": "deleteWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Remove a webhook",
        "description": "Stops events going to the address. Adding it again makes a new signing secret.\n\nScope: `webhooks:manage`.",
        "x-lina-scope": "webhooks:manage",
        "x-lina-module": null,
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The webhook's id."
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "responses": {
          "200": {
            "description": "The webhook is removed.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                },
                "example": {
                  "id": "5d9a3c01e7b2",
                  "object": "webhook",
                  "deleted": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "402": {
            "$ref": "#/components/responses/Error402"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    }
  },
  "webhooks": {
    "lina.event": {
      "post": {
        "summary": "An event Lina sends to a webhook",
        "description": "Lina POSTs one thin event to the address of each webhook subscribed to its type. The body has ids only. The `X-Lina-Signature` header is `t=<unix seconds>,v1=<hex>`, where `v1` is the HMAC-SHA256 of `<t>.<body>` with the webhook's signing secret. Refuse a delivery whose `t` is older than 5 minutes. Answer with any 2xx. A delivery is tried once, so fetch anything you missed from the API.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              },
              "example": {
                "id": "evt_0123456789abcdef01234567",
                "type": "call.received",
                "created": 1793232000,
                "data": {
                  "call_id": "CA0000000000000000000000000000000a"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Lina-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Received."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Lina API key",
        "description": "A Lina API key from Settings, API access, sent as `Authorization: Bearer <key>`."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string",
                "description": "A plain sentence. Safe to show a person; never a secret."
              },
              "type": {
                "type": "string",
                "enum": [
                  "authentication_error",
                  "permission_error",
                  "invalid_request_error",
                  "not_found_error",
                  "conflict",
                  "rate_limit_error",
                  "billing",
                  "api_error"
                ]
              },
              "code": {
                "type": "string",
                "description": "A stable word. Branch on this.",
                "examples": [
                  "missing_api_key",
                  "invalid_api_key",
                  "account_paused",
                  "payment_required",
                  "missing_scope",
                  "module_disabled"
                ]
              },
              "param": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The parameter at fault, when there is one."
              },
              "request_id": {
                "type": "string",
                "description": "Quote this when you write to support."
              },
              "resets_at": {
                "type": "string",
                "description": "On the two monthly 429s: when the count starts again (ISO 8601)."
              }
            },
            "required": [
              "message",
              "type",
              "code",
              "param",
              "request_id"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "Usage": {
        "type": "object",
        "properties": {
          "prompt_tokens": {
            "type": "integer"
          },
          "completion_tokens": {
            "type": "integer"
          },
          "total_tokens": {
            "type": "integer"
          }
        },
        "required": [
          "prompt_tokens",
          "completion_tokens",
          "total_tokens"
        ]
      },
      "ChatMessage": {
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "system",
              "developer",
              "user",
              "assistant"
            ]
          },
          "content": {
            "description": "Text, or a list of text parts. At most 8,000 characters.",
            "oneOf": [
              {
                "type": "string",
                "maxLength": 8000
              },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "const": "text"
                    },
                    "text": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "type",
                    "text"
                  ]
                }
              }
            ]
          }
        },
        "required": [
          "role",
          "content"
        ]
      },
      "ChatCompletionRequest": {
        "type": "object",
        "properties": {
          "model": {
            "type": "string",
            "enum": [
              "lina"
            ],
            "description": "This API serves one model. Any other id is 400 `model_not_found`."
          },
          "messages": {
            "type": "array",
            "minItems": 1,
            "maxItems": 80,
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            },
            "description": "The conversation so far. The last message must be a `user` message."
          },
          "stream": {
            "type": "boolean",
            "default": false
          },
          "stream_options": {
            "type": "object",
            "properties": {
              "include_usage": {
                "type": "boolean",
                "description": "Send a final chunk with the token counts."
              }
            }
          }
        },
        "required": [
          "model",
          "messages"
        ]
      },
      "ChatCompletion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "const": "chat.completion"
          },
          "created": {
            "type": "integer"
          },
          "model": {
            "const": "lina"
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer"
                },
                "message": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "const": "assistant"
                    },
                    "content": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "role",
                    "content"
                  ]
                },
                "finish_reason": {
                  "const": "stop"
                }
              },
              "required": [
                "index",
                "message",
                "finish_reason"
              ]
            }
          },
          "usage": {
            "$ref": "#/components/schemas/Usage"
          }
        },
        "required": [
          "id",
          "object",
          "created",
          "model",
          "choices",
          "usage"
        ]
      },
      "AnswerRequest": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8000
          },
          "context": {
            "type": "string",
            "maxLength": 8000,
            "description": "Background from your software, folded in like a system message of the chat endpoint: it can shape the tone and format of the answer and cannot outrank Lina's own rules."
          }
        },
        "required": [
          "question"
        ]
      },
      "Answer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "const": "answer"
          },
          "answer": {
            "type": "string"
          },
          "usage": {
            "$ref": "#/components/schemas/Usage"
          },
          "model": {
            "const": "lina"
          }
        },
        "required": [
          "id",
          "object",
          "answer",
          "usage",
          "model"
        ]
      },
      "Model": {
        "type": "object",
        "properties": {
          "id": {
            "const": "lina"
          },
          "object": {
            "const": "model"
          },
          "created": {
            "type": "integer"
          },
          "owned_by": {
            "const": "lina"
          }
        },
        "required": [
          "id",
          "object",
          "created",
          "owned_by"
        ]
      },
      "ModelList": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Model"
            }
          }
        },
        "required": [
          "object",
          "data"
        ]
      },
      "KnowledgeInput": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 200
          },
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "The fact itself, in a sentence or more."
          },
          "tags": {
            "type": "array",
            "maxItems": 8,
            "items": {
              "type": "string",
              "maxLength": 40
            }
          }
        },
        "required": [
          "body"
        ]
      },
      "KnowledgeCard": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "const": "knowledge"
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "description": "`api:<key id>` for a card the API added."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "object",
          "title",
          "body",
          "source",
          "tags",
          "created_at"
        ]
      },
      "KnowledgeList": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KnowledgeCard"
            }
          },
          "has_more": {
            "type": "boolean"
          }
        },
        "required": [
          "object",
          "data",
          "has_more"
        ]
      },
      "Deleted": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "type": "string"
          },
          "deleted": {
            "const": true
          }
        },
        "required": [
          "id",
          "object",
          "deleted"
        ]
      },
      "CallRow": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The call's id (the carrier's call sid)."
          },
          "object": {
            "const": "call"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "duration_seconds": {
            "type": [
              "integer",
              "null"
            ]
          },
          "caller_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "The number the caller rang from, when it was not withheld."
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "tag": {
            "type": [
              "string",
              "null"
            ]
          },
          "resolved": {
            "type": "boolean"
          },
          "callback_needed": {
            "type": "boolean"
          },
          "callback_done": {
            "type": "boolean"
          },
          "voicemail": {
            "type": "boolean"
          },
          "escalated": {
            "type": "boolean"
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          },
          "summary_redacted": {
            "type": "boolean",
            "description": "True when the summary was withheld because the call took a payment."
          }
        },
        "required": [
          "id",
          "object",
          "started_at",
          "ended_at",
          "duration_seconds",
          "caller_number",
          "status",
          "tag",
          "resolved",
          "callback_needed",
          "callback_done",
          "voicemail",
          "escalated",
          "summary",
          "summary_redacted"
        ],
        "description": "A call as the list shows it."
      },
      "Call": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The call's id (the carrier's call sid)."
          },
          "object": {
            "const": "call"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "duration_seconds": {
            "type": [
              "integer",
              "null"
            ]
          },
          "caller_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "The number the caller rang from, when it was not withheld."
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "tag": {
            "type": [
              "string",
              "null"
            ]
          },
          "resolved": {
            "type": "boolean"
          },
          "callback_needed": {
            "type": "boolean"
          },
          "callback_done": {
            "type": "boolean"
          },
          "voicemail": {
            "type": "boolean"
          },
          "escalated": {
            "type": "boolean"
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          },
          "summary_redacted": {
            "type": "boolean",
            "description": "True when the summary was withheld because the call took a payment."
          },
          "callback_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Withheld when the call took a payment."
          },
          "transcript": {
            "type": "array",
            "description": "Only with the `calls:transcripts` scope.",
            "items": {
              "type": "object",
              "properties": {
                "role": {
                  "type": "string",
                  "enum": [
                    "agent",
                    "caller"
                  ]
                },
                "text": {
                  "type": "string"
                }
              },
              "required": [
                "role",
                "text"
              ]
            }
          },
          "transcript_redacted": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "object",
          "started_at",
          "ended_at",
          "duration_seconds",
          "caller_number",
          "status",
          "tag",
          "resolved",
          "callback_needed",
          "callback_done",
          "voicemail",
          "escalated",
          "summary",
          "summary_redacted"
        ],
        "description": "A call in full. Never the audio, a payment or a cost."
      },
      "CallList": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CallRow"
            }
          },
          "has_more": {
            "type": "boolean"
          }
        },
        "required": [
          "object",
          "data",
          "has_more"
        ]
      },
      "TextRequest": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string",
            "maxLength": 32,
            "description": "A US phone number."
          },
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1600
          }
        },
        "required": [
          "to",
          "body"
        ]
      },
      "Text": {
        "type": "object",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The carrier's id for the text."
          },
          "object": {
            "const": "text"
          },
          "status": {
            "type": "string",
            "description": "`sent`, or `already_sent` for a repeat of the same Idempotency-Key."
          },
          "segments": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "object",
          "status",
          "segments"
        ]
      },
      "UsageReport": {
        "type": "object",
        "properties": {
          "object": {
            "const": "usage"
          },
          "plan": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "key": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "month": {
            "type": "string"
          },
          "resets_at": {
            "type": "string"
          },
          "ledger_readable": {
            "type": "boolean"
          },
          "allowances": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "used": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "limit": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "percent": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "reached": {
                  "type": "boolean"
                }
              }
            }
          },
          "today": {
            "type": "object",
            "properties": {
              "answers": {
                "type": "integer"
              }
            }
          },
          "api": {
            "type": "object",
            "properties": {
              "answers_this_month": {
                "type": "integer"
              },
              "answers_today": {
                "type": "integer"
              },
              "keys": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "key_id": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "answers_this_month": {
                      "type": "integer"
                    },
                    "answers_today": {
                      "type": "integer"
                    },
                    "monthly_answer_cap": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "required": [
          "object",
          "allowances",
          "api"
        ],
        "description": "What the organization and each key used this month. Never a cost."
      },
      "WebhookInput": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "maxLength": 500,
            "description": "A public http(s) address."
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "enum": [
                "chat.handoff_requested",
                "call.received",
                "call.escalated",
                "text.received",
                "form.submitted",
                "email.received",
                "knowledge.updated",
                "usage.allowance_reached",
                "*"
              ]
            },
            "default": [
              "*"
            ]
          }
        },
        "required": [
          "url"
        ]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "const": "webhook"
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "format": {
            "const": "v1"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "secret": {
            "type": "string",
            "description": "Only in the answer to the request that made it. Keep it: it is never shown again."
          }
        },
        "required": [
          "id",
          "object",
          "url",
          "events",
          "format",
          "created_at"
        ]
      },
      "WebhookList": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "delivery_enabled": {
            "type": "boolean",
            "description": "False when the organization has switched delivery to partner systems off: nothing is sent until it is on."
          }
        },
        "required": [
          "object",
          "data",
          "delivery_enabled"
        ]
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "`evt_` and 24 hex characters."
          },
          "type": {
            "type": "string",
            "enum": [
              "chat.handoff_requested",
              "call.received",
              "call.escalated",
              "text.received",
              "form.submitted",
              "email.received",
              "knowledge.updated",
              "usage.allowance_reached"
            ]
          },
          "created": {
            "type": "integer",
            "description": "Unix seconds."
          },
          "data": {
            "type": "object",
            "properties": {},
            "description": "Ids only: call_id, knowledge_id, session_id. Fetch the rest with the API."
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "data"
        ]
      }
    },
    "parameters": {
      "Idempotency-Key": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "1 to 64 letters, digits and `. _ : -`. The same request with the same key within 24 hours returns the first answer instead of doing the work again; the same key with a different request is 422 `idempotency_key_reused`.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 64,
          "pattern": "^[A-Za-z0-9._:\\-]{1,64}$"
        }
      }
    },
    "headers": {
      "X-Request-ID": {
        "description": "Quote this when you write to support. It is also `error.request_id` on a failure.",
        "schema": {
          "type": "string"
        }
      },
      "X-RateLimit-Limit": {
        "description": "Requests a minute this key may make.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "An estimate of what is left of the minute.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Reset": {
        "description": "Seconds until a slot frees.",
        "schema": {
          "type": "integer"
        }
      },
      "X-Lina-Ignored-Params": {
        "description": "Parameters the request carried that Lina owns or does not use.",
        "schema": {
          "type": "string"
        }
      },
      "Idempotent-Replayed": {
        "description": "`true` when this is the answer to an earlier request with the same Idempotency-Key.",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "Error400": {
        "description": "Bad request. Codes: `invalid_json`, `invalid_request_body`, `invalid_request`, `bad_request`, `invalid_value`, `missing_required_parameter`, `model_not_found`, `unsupported_parameter`, `empty_array`, `array_above_max_length`, `string_above_max_length`, `invalid_cursor`, `invalid_idempotency_key`, `invalid_event`, `invalid_url`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error401": {
        "description": "Unauthorized. Codes: `missing_api_key`, `invalid_api_key`, `unauthorized`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error402": {
        "description": "Payment required. Codes: `account_paused`, `payment_required`, `no_credits`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error403": {
        "description": "Forbidden. Codes: `missing_scope`, `module_disabled`, `secret_key_in_browser`, `knowledge_read_disabled`, `reserved_row`, `one_to_one_only`, `no_module`, `not_registered`, `forbidden`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error404": {
        "description": "Not found. Codes: `wrong_host`, `not_found`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error405": {
        "description": "Method not allowed. Codes: `method_not_allowed`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error409": {
        "description": "Conflict. Codes: `idempotency_in_progress`, `conflict`, `too_many_cards`, `too_many_cards_today`, `too_many_webhooks`, `quiet_hours`, `voter_quiet_hours`, `in_progress`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error413": {
        "description": "Request too large. Codes: `request_too_large`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error422": {
        "description": "Unprocessable. Codes: `invalid_request`, `idempotency_key_reused`, `body_too_short`, `reserved_line`, `labeled_fact`, `reserved_text`, `reserved_tag`, `bad_number`, `too_long`, `no_consent`, `opted_out`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error429": {
        "description": "Too many requests. Codes: `rate_limit_exceeded`, `allowance_reached`, `key_allowance_reached`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error500": {
        "description": "Server error. Codes: `internal_error`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error502": {
        "description": "Bad gateway. Codes: `failed_unknown`, `twilio_unknown`, `text_failed`, `model_error`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error503": {
        "description": "Service unavailable. Codes: `paused`, `store_unavailable`, `twilio_error`, `service_busy`, `service_unavailable`, `api_paused`.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/X-Request-ID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
