{
  "openapi": "3.1.0",
  "info": {
    "title": "Agent Lab AI Gateway",
    "version": "2026-10-23",
    "description": "The Gateway's /v1 endpoints. Error codes: https://agentlab.cresclab.com/docs/en/gateway/errors. Guide: https://agentlab.cresclab.com/docs/en/gateway"
  },
  "servers": [
    {
      "url": "https://api.agentlab.cresclab.com"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "paths": {
    "/v1/chat/completions": {
      "post": {
        "summary": "OpenAI Chat Completions",
        "description": "Any model the workspace allows. model is auto or a name from GET /v1/models; the response names the model that answered and adds agentlab_decision.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Routing"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The model's answer, or a text/event-stream when stream is true.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              },
              "X-Agentlab-Decision": {
                "$ref": "#/components/headers/Decision"
              },
              "X-Agentlab-Assessment": {
                "$ref": "#/components/headers/Assessment"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/messages": {
      "post": {
        "summary": "Anthropic Messages",
        "description": "Relayed to a Claude model as sent, apart from model.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Routing"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["model", "max_tokens", "messages"],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "max_tokens": {
                    "type": "integer"
                  },
                  "messages": {
                    "type": "array"
                  },
                  "metadata": {
                    "type": "object",
                    "properties": {
                      "user_id": {
                        "type": "string",
                        "description": "Recorded as the request's end user."
                      }
                    }
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The model's answer, or a text/event-stream when stream is true.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              },
              "X-Agentlab-Decision": {
                "$ref": "#/components/headers/Decision"
              },
              "X-Agentlab-Assessment": {
                "$ref": "#/components/headers/Assessment"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/messages/count_tokens": {
      "post": {
        "summary": "Anthropic token counting",
        "description": "Not metered.",
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token count.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "input_tokens": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/responses": {
      "post": {
        "summary": "OpenAI Responses",
        "description": "Relayed to an OpenAI model as sent, apart from model; store is sent as false. previous_response_id, conversation, prompt, item references, file_search and image_generation are refused.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Routing"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["model", "input"],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "input": {},
                  "user": {
                    "type": "string",
                    "description": "Recorded as the request's end user."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The model's answer, or a text/event-stream when stream is true.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              },
              "X-Agentlab-Decision": {
                "$ref": "#/components/headers/Decision"
              },
              "X-Agentlab-Assessment": {
                "$ref": "#/components/headers/Assessment"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/embeddings": {
      "post": {
        "summary": "OpenAI embeddings",
        "description": "Relayed to an embeddings model as sent, apart from model. The model is named; auto is refused. Members other than model, input, dimensions, encoding_format and user are refused. Settled by the input tokens the provider reports.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["model", "input"],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "An embeddings model enabled for the workspace."
                  },
                  "input": {
                    "description": "A string, a list of up to 2048 strings, a list of token ids or a list of token id lists."
                  },
                  "dimensions": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "encoding_format": {
                    "type": "string",
                    "enum": ["float", "base64"]
                  },
                  "user": {
                    "type": "string",
                    "description": "Recorded as the request's end user."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The embeddings, as the provider answered with model replaced.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/audio/transcriptions": {
      "post": {
        "summary": "OpenAI audio transcriptions",
        "description": "Relayed to a transcription model as sent, apart from model. stream is refused. Settled by the audio duration the provider reports, or a WAV or MP3 file measures, for a model priced by the minute; by the reported tokens for a model priced by tokens.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["model", "file"],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "A model of this kind enabled for the workspace; auto is refused."
                  },
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "language": {
                    "type": "string"
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "response_format": {
                    "type": "string"
                  },
                  "temperature": {
                    "type": "number"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The transcription, in the response format asked for.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/audio/speech": {
      "post": {
        "summary": "OpenAI audio speech",
        "description": "Relayed to a speech model as sent, apart from model. response_format is mp3, wav or pcm, whose length the Gateway measures; settled by that duration and the input text.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["model", "input", "voice"],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "A model of this kind enabled for the workspace; auto is refused."
                  },
                  "input": {
                    "type": "string",
                    "maxLength": 4096
                  },
                  "voice": {},
                  "instructions": {
                    "type": "string"
                  },
                  "response_format": {
                    "type": "string",
                    "enum": ["mp3", "wav", "pcm"]
                  },
                  "speed": {
                    "type": "number",
                    "minimum": 0.25,
                    "maximum": 4
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The audio file.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              }
            },
            "content": {
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/pcm": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/images/generations": {
      "post": {
        "summary": "OpenAI image generation",
        "description": "Relayed to an image model as sent, apart from model. stream is refused. Settled by the tokens the provider reports for a model priced by tokens, or by the images returned for a model priced per image.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["model", "prompt"],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "A model of this kind enabled for the workspace; auto is refused."
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "n": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10
                  },
                  "size": {
                    "type": "string"
                  },
                  "quality": {
                    "type": "string"
                  },
                  "response_format": {
                    "type": "string"
                  },
                  "output_format": {
                    "type": "string"
                  },
                  "output_compression": {
                    "type": "integer"
                  },
                  "background": {
                    "type": "string"
                  },
                  "user": {
                    "type": "string",
                    "description": "Recorded as the request's end user."
                  },
                  "moderation": {
                    "type": "string"
                  },
                  "style": {
                    "type": "string"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The images.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/images/edits": {
      "post": {
        "summary": "OpenAI image edits",
        "description": "Relayed to an image model as sent, apart from model. stream is refused. Settled as image generation is.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["model", "prompt", "image"],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "A model of this kind enabled for the workspace; auto is refused."
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "n": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10
                  },
                  "size": {
                    "type": "string"
                  },
                  "quality": {
                    "type": "string"
                  },
                  "response_format": {
                    "type": "string"
                  },
                  "output_format": {
                    "type": "string"
                  },
                  "output_compression": {
                    "type": "integer"
                  },
                  "background": {
                    "type": "string"
                  },
                  "user": {
                    "type": "string",
                    "description": "Recorded as the request's end user."
                  },
                  "image": {
                    "type": "string",
                    "format": "binary"
                  },
                  "mask": {
                    "type": "string",
                    "format": "binary"
                  },
                  "input_fidelity": {
                    "type": "string"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The edited images.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/videos": {
      "post": {
        "summary": "OpenAI video generation",
        "description": "Starts a video job on a video model, relayed as sent apart from model. The job keeps its reservation until a read of it sees it complete, which settles it at the seconds the provider reports.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["model", "prompt"],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "A model of this kind enabled for the workspace; auto is refused."
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "seconds": {},
                  "size": {
                    "type": "string"
                  },
                  "input_reference": {
                    "type": "object",
                    "description": "The reference image as an https URL or a data:image URL. A file_id is refused: it would name a file in the provider account every workspace shares.",
                    "required": ["image_url"],
                    "properties": {
                      "image_url": {
                        "type": "string"
                      }
                    },
                    "additionalProperties": false
                  }
                },
                "additionalProperties": false
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["model", "prompt"],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "A model of this kind enabled for the workspace; auto is refused."
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "seconds": {},
                  "size": {
                    "type": "string"
                  },
                  "input_reference": {
                    "type": "string",
                    "format": "binary",
                    "description": "The reference image, uploaded as a file; a text value (a file id) is refused."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The video job.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/videos/{videoId}": {
      "get": {
        "summary": "Video job",
        "description": "A video job this API key created, as the provider reports it. Another key's job is 404.",
        "parameters": [
          {
            "name": "videoId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The video job.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No video with this id was created with this API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/videos/{videoId}/content": {
      "get": {
        "summary": "Video content",
        "description": "The finished video (or its thumbnail or spritesheet) of a job this API key created, relayed as it arrives.",
        "parameters": [
          {
            "name": "videoId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "variant",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["video", "thumbnail", "spritesheet"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The video file.",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No video with this id was created with this API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/models": {
      "get": {
        "summary": "List models",
        "description": "auto and the models this key may name. Anthropic list shape when anthropic-version or x-api-key is sent, otherwise OpenAI's.",
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Model list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/outcomes": {
      "post": {
        "summary": "Report a task outcome",
        "description": "Says, after the answer, whether a request or the agent run it belongs to succeeded. Name the request by the X-Request-Id (or chatcmpl_ id) its answer carried, or the run by the trace id its requests arrived with in traceparent; exactly one. Any key of the workspace may report, within 31 days of the request (for a run, its most recent request). A later report replaces the earlier one; a request's own outcome wins over its run's. Usage counts cost per successful task only from reported outcomes.",
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": ["outcome"],
                "properties": {
                  "request_id": {
                    "type": "string",
                    "description": "The X-Request-Id, or the chatcmpl_ id, of the request's answer.",
                    "pattern": "^(chatcmpl_)?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
                  },
                  "trace_id": {
                    "type": "string",
                    "description": "The trace id of the traceparent the run's requests arrived with.",
                    "pattern": "^[0-9a-f]{32}$"
                  },
                  "outcome": {
                    "type": "string",
                    "enum": ["success", "failure"]
                  }
                },
                "oneOf": [
                  {
                    "required": ["request_id"]
                  },
                  {
                    "required": ["trace_id"]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What was recorded and how many requests it applies to.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "subject": {
                      "type": "object",
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": ["request", "trace"]
                        },
                        "id": {
                          "type": "string"
                        }
                      }
                    },
                    "outcome": {
                      "type": "string",
                      "enum": ["success", "failure"]
                    },
                    "requests": {
                      "type": "integer",
                      "minimum": 1
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_outcome: not exactly one subject, an id of the wrong shape, or an outcome other than success or failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "outcome_subject_not_found: no such request or run in this key's workspace; the same answer for another workspace's id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "outcome_window_closed: the request, or the run's most recent request, was prepared more than 31 days ago.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many failed key attempts from this address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/gateway/readiness": {
      "get": {
        "summary": "Readiness",
        "description": "200 when this Gateway server can serve, 503 while starting, reloading or draining.",
        "security": [],
        "responses": {
          "200": {
            "description": "Ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Readiness"
                }
              }
            }
          },
          "503": {
            "description": "Not ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Readiness"
                }
              }
            }
          }
        }
      }
    },
    "/v1/prompts/{promptId}/completions": {
      "post": {
        "summary": "Call a workspace prompt",
        "description": "Portkey-style prompt call. The path names a prompt from the workspace's prompt library by id or slug; append @<version> to pin a version, otherwise the published version answers. The body carries variables, which must be exactly the prompt's, and any Chat Completions member except messages, which overrides what the prompt sets. Answered exactly as /v1/chat/completions, through the same key, limits, auto routing and usage; the request records the prompt and version.",
        "parameters": [
          {
            "name": "promptId",
            "in": "path",
            "required": true,
            "description": "The prompt's id or slug, optionally followed by @<version>.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+(@[1-9][0-9]{0,3})?$"
            }
          },
          {
            "$ref": "#/components/parameters/Routing"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PromptCompletionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The model's answer, or a text/event-stream when stream is true.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-Agentlab-Model": {
                "$ref": "#/components/headers/Model"
              },
              "X-Agentlab-Decision": {
                "$ref": "#/components/headers/Decision"
              },
              "X-Agentlab-Assessment": {
                "$ref": "#/components/headers/Assessment"
              },
              "X-Agentlab-Prompt": {
                "$ref": "#/components/headers/Prompt"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Refused request. See the error catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or not accepted key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not allowed for this key or workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The key's workspace has no prompt, or no such version, by that name (prompt_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or out of allowance. Retry-After and X-Should-Retry say whether to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The provider failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Gateway unavailable or settlement pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "A Gateway key, al_gw_<id>.<secret>."
      },
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    },
    "parameters": {
      "Routing": {
        "name": "X-AgentLab-Routing",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "enum": ["auto", "auto:cost", "auto:balanced", "auto:quality"]
        },
        "description": "Let the Gateway choose the model although the body names one, with that preference."
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 128
        }
      }
    },
    "headers": {
      "RequestId": {
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "The request id shown on the usage page and in the export."
      },
      "Model": {
        "schema": {
          "type": "string"
        },
        "description": "The model that answered."
      },
      "Decision": {
        "schema": {
          "type": "string",
          "enum": [
            "requested_model",
            "auto_assessed",
            "auto_reused",
            "auto_uncertain",
            "auto_assessment_failed",
            "auto_assessment_timeout",
            "auto_budget_guard"
          ]
        }
      },
      "Assessment": {
        "schema": {
          "type": "string"
        },
        "description": "With auto, task/complexity or unavailable."
      },
      "Prompt": {
        "schema": {
          "type": "string"
        },
        "description": "The prompt version that answered, <prompt id>@<version>."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "OpenAI shape {error:{message,type,param,code}} on Chat Completions, Responses and /v1/models; Anthropic shape {type:'error',error:{type,message,code?}} on Messages. Codes: https://agentlab.cresclab.com/docs/en/gateway/errors",
        "additionalProperties": true,
        "properties": {
          "type": {
            "type": "string"
          },
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "param": {
                "type": ["string", "null"]
              },
              "code": {
                "type": ["string", "null"]
              }
            }
          }
        }
      },
      "ChatCompletionRequest": {
        "type": "object",
        "required": ["model", "messages"],
        "additionalProperties": true,
        "properties": {
          "model": {
            "type": "string",
            "description": "auto, auto:cost, auto:quality or a name from GET /v1/models."
          },
          "messages": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "object"
            }
          },
          "tools": {
            "type": "array",
            "maxItems": 100
          },
          "max_completion_tokens": {
            "type": "integer"
          },
          "max_tokens": {
            "type": "integer"
          },
          "stream": {
            "type": "boolean"
          },
          "stream_options": {
            "type": "object",
            "properties": {
              "include_usage": {
                "type": "boolean"
              }
            }
          },
          "response_format": {
            "type": "object"
          },
          "user": {
            "type": "string",
            "description": "Recorded as the request's end user."
          },
          "agentlab": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "schema_version": {
                "const": 1
              },
              "tool_calling": {
                "type": "boolean"
              },
              "vision": {
                "type": "boolean"
              },
              "structured_output": {
                "type": "boolean"
              },
              "minimum_context_tokens": {
                "type": "integer",
                "minimum": 0
              }
            }
          }
        }
      },
      "Readiness": {
        "type": "object",
        "required": ["status", "commit"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["ready", "pending"]
          },
          "configuration": {
            "type": "string"
          },
          "commit": {
            "type": "string"
          }
        }
      },
      "PromptCompletionRequest": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "variables": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "One string for each {{variable}} the prompt uses; a missing or extra one is refused with prompt_variables_mismatch."
          },
          "model": {
            "type": "string",
            "description": "Overrides the prompt's model: auto or a name from GET /v1/models."
          },
          "stream": {
            "type": "boolean"
          },
          "user": {
            "type": "string",
            "description": "Recorded as the request's end user."
          }
        }
      }
    }
  }
}
