openapi: 3.0.1 info: title: Keywords AI API description: >- Keywords AI is an LLM observability and gateway platform. This specification documents the publicly documented REST surface served from https://api.keywordsai.co/api: the OpenAI-compatible chat completions proxy, the asynchronous request-logging endpoint, prompt and prompt-version management, threads, traces, evaluators, users (customers), datasets, and experiments. All endpoints authenticate with a Bearer API key. (Keywords AI is rebranding to Respan; the keywordsai.co host and API remain active.) termsOfService: https://www.keywordsai.co/terms-of-service contact: name: Keywords AI Support url: https://www.keywordsai.co email: team@keywordsai.co version: '1.0' servers: - url: https://api.keywordsai.co/api description: Keywords AI production API base. security: - bearerAuth: [] tags: - name: Gateway description: OpenAI-compatible LLM proxy (chat completions). - name: Logging description: Asynchronous request / span logging. - name: Prompts description: Prompt and prompt-version management. - name: Threads description: Multi-turn conversation threads. - name: Traces description: OpenTelemetry-aligned distributed traces. - name: Evaluators description: Output-scoring evaluators. - name: Users description: End-user (customer) analytics. - name: Datasets description: Datasets and dataset logs. - name: Experiments description: Prompt / model experiments. paths: /chat/completions: post: operationId: createChatCompletion tags: - Gateway summary: Create a chat completion description: >- OpenAI-compatible chat completions through the Keywords AI gateway. Routes to 250+ models behind a single endpoint, with optional streaming (Server-Sent Events when `stream` is true), tool calling, structured outputs, fallbacks, load balancing, caching, and automatic logging. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ChatCompletionRequest' example: model: gpt-4o-mini messages: - role: user content: Reply with exactly ok. max_tokens: 16 temperature: 0 responses: '200': description: A chat completion (or, when stream=true, an SSE stream of chunks). content: application/json: schema: $ref: '#/components/schemas/ChatCompletionResponse' text/event-stream: schema: type: string description: 'data-only Server-Sent Events terminated by a [DONE] sentinel.' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' /request-logs/: post: operationId: createRequestLog tags: - Logging summary: Create a request log (span) description: >- Asynchronously ingest telemetry for an LLM call that was not routed through the gateway proxy. The legacy alias `/request-logs/create/` remains supported. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RequestLog' example: model: gpt-4o prompt_messages: - role: user content: Hello completion_message: role: assistant content: Hi there! prompt_tokens: 8 completion_tokens: 4 cost: 0.00012 latency: 0.42 customer_identifier: user_123 responses: '200': description: Log accepted. content: application/json: schema: $ref: '#/components/schemas/SimpleMessage' '401': $ref: '#/components/responses/Unauthorized' /prompts/: post: operationId: createPrompt tags: - Prompts summary: Create a prompt requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PromptCreate' example: name: customer_support responses: '201': description: Prompt created. content: application/json: schema: $ref: '#/components/schemas/Prompt' '401': $ref: '#/components/responses/Unauthorized' get: operationId: listPrompts tags: - Prompts summary: List prompts responses: '200': description: A list of prompts. content: application/json: schema: type: object properties: results: type: array items: $ref: '#/components/schemas/Prompt' /prompts/{prompt_id}/: parameters: - $ref: '#/components/parameters/PromptId' get: operationId: retrievePrompt tags: - Prompts summary: Retrieve a prompt responses: '200': description: A prompt. content: application/json: schema: $ref: '#/components/schemas/Prompt' '404': $ref: '#/components/responses/NotFound' patch: operationId: updatePrompt tags: - Prompts summary: Update a prompt requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PromptCreate' responses: '200': description: Prompt updated. content: application/json: schema: $ref: '#/components/schemas/Prompt' delete: operationId: deletePrompt tags: - Prompts summary: Delete a prompt responses: '204': description: Prompt deleted. /prompts/{prompt_id}/versions/: parameters: - $ref: '#/components/parameters/PromptId' post: operationId: createPromptVersion tags: - Prompts summary: Create a prompt version requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PromptVersion' example: model: gpt-4o messages: - role: system content: You are a helpful {{role}} assistant. temperature: 0.7 responses: '201': description: Prompt version created. content: application/json: schema: $ref: '#/components/schemas/PromptVersion' get: operationId: listPromptVersions tags: - Prompts summary: List prompt versions responses: '200': description: A list of prompt versions. content: application/json: schema: type: object properties: results: type: array items: $ref: '#/components/schemas/PromptVersion' /log_threads/: post: operationId: listThreads tags: - Threads summary: List threads description: Retrieve conversation threads matching the supplied filters, with pagination. requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/ListFilter' responses: '200': description: A paginated list of threads. content: application/json: schema: $ref: '#/components/schemas/PaginatedList' /traces/list/: post: operationId: listTraces tags: - Traces summary: List traces description: Retrieve traces (OpenTelemetry-aligned span trees) with filtering and pagination. requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/ListFilter' responses: '200': description: A paginated list of traces. content: application/json: schema: $ref: '#/components/schemas/PaginatedList' /traces/{trace_id}/: parameters: - name: trace_id in: path required: true schema: type: string get: operationId: retrieveTrace tags: - Traces summary: Retrieve a trace responses: '200': description: A trace with its spans. content: application/json: schema: $ref: '#/components/schemas/Trace' '404': $ref: '#/components/responses/NotFound' delete: operationId: deleteTrace tags: - Traces summary: Delete a trace responses: '204': description: Trace deleted. /evaluators/: post: operationId: createEvaluator tags: - Evaluators summary: Create an evaluator requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Evaluator' responses: '201': description: Evaluator created. content: application/json: schema: $ref: '#/components/schemas/Evaluator' /evaluators/list/: post: operationId: listEvaluators tags: - Evaluators summary: List evaluators description: Retrieve evaluators matching the supplied filters. requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/ListFilter' responses: '200': description: A paginated list of evaluators. content: application/json: schema: $ref: '#/components/schemas/PaginatedList' /evaluators/{evaluator_id}/run/: parameters: - name: evaluator_id in: path required: true schema: type: string post: operationId: runEvaluator tags: - Evaluators summary: Run an evaluator description: Execute an evaluator against supplied inputs/logs and return scores. requestBody: required: true content: application/json: schema: type: object properties: input: type: string output: type: string metadata: type: object additionalProperties: true responses: '200': description: Evaluation result with score(s). content: application/json: schema: $ref: '#/components/schemas/EvaluationResult' /users/list/: post: operationId: listUsers tags: - Users summary: List users (customers) description: >- Retrieve end-user (customer) records in your organization with analytics and budget fields. Supports filtering by customer_identifier, name, email, number_of_requests, total_tokens, total_cost, and active_days. parameters: - name: page in: query schema: type: integer default: 1 - name: page_size in: query schema: type: integer default: 50 maximum: 1000 - name: environment in: query schema: type: string enum: - prod - test requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/ListFilter' responses: '200': description: A paginated list of users (customers). content: application/json: schema: $ref: '#/components/schemas/PaginatedList' /datasets/: post: operationId: createDataset tags: - Datasets summary: Create a dataset requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Dataset' responses: '201': description: Dataset created. content: application/json: schema: $ref: '#/components/schemas/Dataset' get: operationId: listDatasets tags: - Datasets summary: List datasets responses: '200': description: A list of datasets. content: application/json: schema: type: object properties: results: type: array items: $ref: '#/components/schemas/Dataset' /experiments/: post: operationId: createExperiment tags: - Experiments summary: Create an experiment requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Experiment' responses: '201': description: Experiment created. content: application/json: schema: $ref: '#/components/schemas/Experiment' components: securitySchemes: bearerAuth: type: http scheme: bearer description: 'Keywords AI API key supplied as the Authorization Bearer header (Authorization: Bearer ).' parameters: PromptId: name: prompt_id in: path required: true schema: type: string description: The prompt identifier (id or slug). responses: Unauthorized: description: Missing or invalid API key. content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: Resource not found. content: application/json: schema: $ref: '#/components/schemas/Error' RateLimited: description: Too many requests. content: application/json: schema: $ref: '#/components/schemas/Error' schemas: Message: type: object required: - role - content properties: role: type: string enum: - system - user - assistant - tool content: type: string name: type: string tool_calls: type: array items: type: object additionalProperties: true ChatCompletionRequest: type: object required: - model - messages properties: model: type: string description: Model identifier (any of the 250+ supported models). messages: type: array items: $ref: '#/components/schemas/Message' stream: type: boolean description: Stream the response token-by-token via Server-Sent Events. default: false temperature: type: number minimum: 0 maximum: 2 max_tokens: type: integer top_p: type: number frequency_penalty: type: number presence_penalty: type: number tools: type: array items: type: object additionalProperties: true response_format: type: object additionalProperties: true customer_identifier: type: string description: End-user identifier for per-user analytics and logging. fallback_models: type: array items: type: string metadata: type: object additionalProperties: true ChatCompletionResponse: type: object properties: id: type: string object: type: string example: chat.completion created: type: integer model: type: string choices: type: array items: type: object properties: index: type: integer message: $ref: '#/components/schemas/Message' finish_reason: type: string usage: type: object properties: prompt_tokens: type: integer completion_tokens: type: integer total_tokens: type: integer RequestLog: type: object required: - model properties: model: type: string prompt_messages: type: array items: $ref: '#/components/schemas/Message' completion_message: $ref: '#/components/schemas/Message' input: description: Universal input (string, object, or array). output: description: Universal output (string, object, or array). prompt_tokens: type: integer completion_tokens: type: integer cost: type: number description: Request cost in USD; auto-calculated if omitted. latency: type: number description: Total request latency in seconds. customer_identifier: type: string status: type: string enum: - success - error timestamp: type: string format: date-time metadata: type: object additionalProperties: true PromptCreate: type: object required: - name properties: name: type: string description: type: string Prompt: type: object properties: id: type: string name: type: string slug: type: string description: type: string current_version: type: integer created_at: type: string format: date-time updated_at: type: string format: date-time PromptVersion: type: object required: - model - messages properties: model: type: string messages: type: array items: $ref: '#/components/schemas/Message' description: type: string temperature: type: number max_tokens: type: integer top_p: type: number frequency_penalty: type: number presence_penalty: type: number variables: type: object additionalProperties: true fallback_models: type: array items: type: string load_balance_models: type: array items: type: object additionalProperties: true tools: type: array items: type: object additionalProperties: true response_format: type: object additionalProperties: true deploy: type: boolean Trace: type: object properties: trace_id: type: string name: type: string start_time: type: string format: date-time end_time: type: string format: date-time spans: type: array items: type: object additionalProperties: true Evaluator: type: object required: - name properties: id: type: string name: type: string type: type: string description: Evaluator type (e.g. llm, code, human). description: type: string definition: type: object additionalProperties: true EvaluationResult: type: object properties: evaluator_id: type: string score: type: number passed: type: boolean reason: type: string Dataset: type: object required: - name properties: id: type: string name: type: string description: type: string created_at: type: string format: date-time Experiment: type: object required: - name properties: id: type: string name: type: string description: type: string columns: type: array items: type: object additionalProperties: true ListFilter: type: object properties: filters: type: object additionalProperties: true page: type: integer default: 1 page_size: type: integer default: 50 sort_by: type: string PaginatedList: type: object properties: count: type: integer next: type: string nullable: true previous: type: string nullable: true results: type: array items: type: object additionalProperties: true SimpleMessage: type: object properties: message: type: string Error: type: object properties: error: type: object properties: message: type: string type: type: string code: type: string