{
  "openapi": "3.1.0",
  "info": {
    "title": "Y-API",
    "summary": "OpenAI- and Anthropic-compatible access to 15+ models behind one key.",
    "description": "One gateway, two protocols, one key. `POST /chat/completions` and `GET /models` speak the OpenAI protocol; `POST /messages` speaks Anthropic's. Both serve the same 15-model catalog, so an Anthropic client can call a DeepSeek or Qwen model and an OpenAI client can call the same model back.\n\n## Before you write a retry loop\n\nRead error.code, not the status code. Running out of credit is HTTP 403 `insufficient_user_quota`, not the 429 most clients expect. The SDK retry set contains 429 but not 403, so the request fails on the first attempt instead of after two pointless round trips — but code that special-cases 429 for \"out of credit\" will never fire here. A model ID that is not in the catalog is HTTP 503 `model_not_found` — which the SDKs do retry, twice, before your program ever sees it. A missing required field is HTTP 500. Each error response below says whether the SDKs retry that status; the full table with measured message text is at https://y-api.bestvirtualgoods.com/docs/errors.\n\n## Not served here\n\n- **HTTP 404** — POST /v1/messages/count_tokens is not implemented. Claude Code and the Anthropic SDK call it to estimate context size before sending a request. Nothing to fix on your side. Clients either skip the estimate or show a warning; chat, streaming and tool use are unaffected.\n- **HTTP 400** — The endpoint does not exist here — /v1/embeddings, /v1/completions and /v1/images/generations all land in this case. The body then claims messages is required, which points at something entirely unrelated to the real problem. This gateway serves chat completions and the Anthropic messages endpoint. If a framework calls an embeddings endpoint under the hood, that part needs a different provider.\n\n## How to read this document\n\nA field is in `required` only if a probe against the live gateway asserted it is always there. Fields outside `required` are typed from the upstream protocol and were seen in real responses, but nothing guarantees their presence. Endpoints absent from this document were not measured — or were measured and found missing, in which case they are listed above rather than described as paths.\n\nCatalog and model enum are a build-time snapshot synced 2026-09-21; failures were measured 2026-09-01. The catalog on its own, no key required: https://y-api.bestvirtualgoods.com/models.json. Machine-readable prices: https://y-api.bestvirtualgoods.com/pricing.json. Everything else: https://y-api.bestvirtualgoods.com/llms.txt.",
    "version": "2026-09-21",
    "termsOfService": "https://y-api.bestvirtualgoods.com/terms",
    "contact": {
      "email": "support@bestvirtualgoods.com",
      "url": "https://y-api.bestvirtualgoods.com/docs"
    },
    "x-generated-by": "scripts/generate-seo-assets.mjs",
    "x-catalog-synced-at": "2026-09-21",
    "x-failures-verified-at": "2026-09-01"
  },
  "externalDocs": {
    "description": "Quickstarts, client compatibility and the measured failure table",
    "url": "https://y-api.bestvirtualgoods.com/docs"
  },
  "servers": [
    {
      "url": "https://api.y-api.bestvirtualgoods.com/v1",
      "description": "Production. Already includes the `/v1` prefix — this is the exact string that goes in an SDK’s `base_url`."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "OpenAI protocol",
      "description": "Drop-in for the OpenAI SDKs: `Authorization: Bearer`, OpenAI request and response shapes."
    },
    {
      "name": "Anthropic protocol",
      "description": "Drop-in for the Anthropic SDKs: `x-api-key`, Anthropic request and response shapes — over the same catalog."
    }
  ],
  "paths": {
    "/chat/completions": {
      "post": {
        "operationId": "createChatCompletion",
        "tags": [
          "OpenAI protocol"
        ],
        "summary": "Create a chat completion",
        "description": "The OpenAI-compatible endpoint. Point any OpenAI SDK at the server URL above and change the model name; nothing else needs to change. Verified against the live gateway: non-streaming text, streaming, tool calls (streamed and not), `response_format: {\"type\":\"json_object\"}`, and `usage` on every response. This endpoint is text-only in practice — image parts are accepted and then ignored by every model in the catalog.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Smallest request that works",
                  "value": {
                    "model": "deepseek/deepseek-v4-flash",
                    "messages": [
                      {
                        "role": "user",
                        "content": "hi"
                      }
                    ],
                    "max_tokens": 64
                  }
                },
                "streaming": {
                  "summary": "Stream, and get usage in the final frame",
                  "value": {
                    "model": "deepseek/deepseek-v4-flash",
                    "messages": [
                      {
                        "role": "user",
                        "content": "hi"
                      }
                    ],
                    "stream": true,
                    "stream_options": {
                      "include_usage": true
                    }
                  }
                },
                "toolCall": {
                  "summary": "Tool call",
                  "value": {
                    "model": "deepseek/deepseek-v4-flash",
                    "messages": [
                      {
                        "role": "user",
                        "content": "What is the weather in Paris?"
                      }
                    ],
                    "tools": [
                      {
                        "type": "function",
                        "function": {
                          "name": "get_weather",
                          "description": "Current weather for a city.",
                          "parameters": {
                            "type": "object",
                            "properties": {
                              "location": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "location"
                            ]
                          }
                        }
                      }
                    ],
                    "tool_choice": "auto"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A completion. `usage` is always present, and `usage.completion_tokens` is what you are billed for — it includes reasoning tokens that never appear in `content`. When `tools` were sent and the model chose to call one, `choices[0].message.tool_calls` carries the call and `finish_reason` is `tool_calls`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletionResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Returned when `stream: true`. OpenAI’s frame format: `data: ` + a JSON chunk per frame, blank line between frames, and a literal `data: [DONE]` at the end. Token text arrives in `choices[0].delta.content`; a streamed tool call arrives as incremental `arguments` fragments on `choices[0].delta.tool_calls[0]`, which must be concatenated before parsing. With `stream_options.include_usage` a final frame carries `usage`."
                },
                "example": "data: {\"choices\":[{\"index\":0,\"delta\":{\"content\":\"Hi\"}}]}\n\ndata: [DONE]\n\n"
              }
            }
          },
          "400": {
            "description": "The official SDKs do not retry this status; it surfaces on the first attempt.\n\n- `error.code`: empty string (Measured on the live endpoint) — The request body is not valid JSON. The upstream doubles its own \"Invalid request:\" prefix, which is cosmetic. Usually a hand-built payload or shell quoting. Validate the JSON before sending; in a shell, keep the body in single quotes. Message returned: `Invalid request: Invalid request: invalid JSON request body`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "malformed-json": {
                    "summary": "new_api_error",
                    "value": {
                      "error": {
                        "message": "Invalid request: Invalid request: invalid JSON request body",
                        "type": "new_api_error",
                        "code": ""
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "The official SDKs do not retry this status; it surfaces on the first attempt.\n\n- `error.code`: empty string (Measured on the live endpoint) — The key does not exist, was revoked, or the Authorization header is missing altogether. Confirm the key still exists on the API Keys page in the console, or create a new one. One thing this is not: a missing \"Bearer \" prefix — the gateway accepts the bare key too, so that is never the cause. Message returned: `Invalid token`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "invalid-key": {
                    "summary": "new_api_error",
                    "value": {
                      "error": {
                        "message": "Invalid token",
                        "type": "new_api_error",
                        "code": ""
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "**Status code misleads.** The official SDKs do not retry this status; it surfaces on the first attempt.\n\n- `insufficient_user_quota` (Confirmed in upstream source, not triggered here) — The account balance reached zero. The message is in Chinese and quotes the remaining balance with a fullwidth ＄, which is why searching for the English text finds nothing. Top up at https://y-api.bestvirtualgoods.com/app/billing. Credit is restored immediately, existing keys keep working, and no code changes. Message returned: `用户额度不足, 剩余额度: ＄0.00`\n- `pre_consume_token_quota_failed` (Measured on the live endpoint) — The account still has credit, but this one key hit the per-key cap set when it was created. The message quotes both the key’s remaining quota and the amount this request needed. Raise or remove that key’s limit on the API Keys page, or switch to a key without a cap. Topping up the account does not help — the cap is per key. Message returned: `token quota is not enough, token remain quota: ＄0.000002, need quota: ＄0.000074`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "quota-exhausted": {
                    "summary": "insufficient_user_quota",
                    "value": {
                      "error": {
                        "message": "用户额度不足, 剩余额度: ＄0.00",
                        "type": "new_api_error",
                        "code": "insufficient_user_quota"
                      }
                    }
                  },
                  "key-limit-reached": {
                    "summary": "pre_consume_token_quota_failed",
                    "value": {
                      "error": {
                        "message": "token quota is not enough, token remain quota: ＄0.000002, need quota: ＄0.000074",
                        "type": "new_api_error",
                        "code": "pre_consume_token_quota_failed"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "**Status code misleads.** The official SDKs retry this status twice by default with exponential backoff. Retrying fixes none of the causes below — read the body on the first failure instead.\n\n- `invalid_request` (Measured on the live endpoint) — A required field is absent from the request body, usually messages. This is a malformed-request error reported as a server error. The message names the field verbatim, so read it rather than the status code. Fix the body; retrying is guaranteed to fail again. Message returned: `field messages is required`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "missing-field": {
                    "summary": "invalid_request",
                    "value": {
                      "error": {
                        "message": "field messages is required",
                        "type": "new_api_error",
                        "code": "invalid_request"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "**Status code misleads.** The official SDKs retry this status twice by default with exponential backoff. Retrying fixes none of the causes below — read the body on the first failure instead.\n\n- `model_not_found` (Measured on the live endpoint) — The model ID is not in this catalog — almost always copied from another provider’s docs (gpt-4o, claude-sonnet-4-5). Nothing is down; there is simply no route for a model that does not exist here. Check the ID against GET /v1/models, which is the authoritative list. Every ID here is vendor/model, for example deepseek/deepseek-v4-flash. Message returned: `No available channel for model gpt-4o under group y-api (distributor)`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "unknown-model": {
                    "summary": "model_not_found",
                    "value": {
                      "error": {
                        "message": "No available channel for model gpt-4o under group y-api (distributor)",
                        "type": "new_api_error",
                        "code": "model_not_found"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Any other failure. The wrapper is the same everywhere. Read error.code, not the status code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/messages": {
      "post": {
        "operationId": "createMessage",
        "tags": [
          "Anthropic protocol"
        ],
        "summary": "Create a message",
        "description": "The Anthropic-compatible endpoint, serving the same catalog as `/chat/completions` — including models that are not Anthropic’s. It authenticates with `x-api-key`, takes `system` as a top-level parameter rather than a message, and requires `max_tokens`. One documented deviation from the official API: the response `id` is a bare hex string with no `msg_` prefix. Everything else in the payload is compliant.",
        "security": [
          {
            "anthropicApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "anthropic-version",
            "in": "header",
            "required": false,
            "description": "Every official Anthropic client sends this, and every verified call to this endpoint included it. Send it.",
            "schema": {
              "type": "string",
              "examples": [
                "2023-06-01"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnthropicMessagesRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "Smallest request that works",
                  "value": {
                    "model": "deepseek/deepseek-v4-flash",
                    "max_tokens": 64,
                    "messages": [
                      {
                        "role": "user",
                        "content": "hi"
                      }
                    ]
                  }
                },
                "withSystem": {
                  "summary": "System prompt as a top-level parameter",
                  "value": {
                    "model": "deepseek/deepseek-v4-flash",
                    "max_tokens": 64,
                    "system": "Answer in one sentence.",
                    "messages": [
                      {
                        "role": "user",
                        "content": "hi"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A message. `content` is an array of blocks: `text` blocks carry the answer, a `tool_use` block carries a tool call and sets `stop_reason` to `tool_use`. Token counts are `usage.input_tokens` and `usage.output_tokens`, not the OpenAI field names.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnthropicMessageResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Returned when `stream: true`. Named SSE events, all six emitted: `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta`, `message_stop`."
                },
                "example": "event: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"Hi\"}}\n\n"
              }
            }
          },
          "401": {
            "description": "The official SDKs do not retry this status; it surfaces on the first attempt.\n\n- `error.code`: empty string (Measured on the live endpoint) — The key does not exist, was revoked, or the Authorization header is missing altogether. Confirm the key still exists on the API Keys page in the console, or create a new one. One thing this is not: a missing \"Bearer \" prefix — the gateway accepts the bare key too, so that is never the cause. Message returned: `Invalid token`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "invalid-key": {
                    "summary": "new_api_error",
                    "value": {
                      "error": {
                        "message": "Invalid token",
                        "type": "new_api_error",
                        "code": ""
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "**Status code misleads.** The official SDKs do not retry this status; it surfaces on the first attempt.\n\n- `insufficient_user_quota` (Confirmed in upstream source, not triggered here) — The account balance reached zero. The message is in Chinese and quotes the remaining balance with a fullwidth ＄, which is why searching for the English text finds nothing. Top up at https://y-api.bestvirtualgoods.com/app/billing. Credit is restored immediately, existing keys keep working, and no code changes. Message returned: `用户额度不足, 剩余额度: ＄0.00`\n- `pre_consume_token_quota_failed` (Measured on the live endpoint) — The account still has credit, but this one key hit the per-key cap set when it was created. The message quotes both the key’s remaining quota and the amount this request needed. Raise or remove that key’s limit on the API Keys page, or switch to a key without a cap. Topping up the account does not help — the cap is per key. Message returned: `token quota is not enough, token remain quota: ＄0.000002, need quota: ＄0.000074`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "quota-exhausted": {
                    "summary": "insufficient_user_quota",
                    "value": {
                      "error": {
                        "message": "用户额度不足, 剩余额度: ＄0.00",
                        "type": "new_api_error",
                        "code": "insufficient_user_quota"
                      }
                    }
                  },
                  "key-limit-reached": {
                    "summary": "pre_consume_token_quota_failed",
                    "value": {
                      "error": {
                        "message": "token quota is not enough, token remain quota: ＄0.000002, need quota: ＄0.000074",
                        "type": "new_api_error",
                        "code": "pre_consume_token_quota_failed"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "**Status code misleads.** The official SDKs retry this status twice by default with exponential backoff. Retrying fixes none of the causes below — read the body on the first failure instead.\n\n- `model_not_found` (Measured on the live endpoint) — The model ID is not in this catalog — almost always copied from another provider’s docs (gpt-4o, claude-sonnet-4-5). Nothing is down; there is simply no route for a model that does not exist here. Check the ID against GET /v1/models, which is the authoritative list. Every ID here is vendor/model, for example deepseek/deepseek-v4-flash. Message returned: `No available channel for model gpt-4o under group y-api (distributor)`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "unknown-model": {
                    "summary": "model_not_found",
                    "value": {
                      "error": {
                        "message": "No available channel for model gpt-4o under group y-api (distributor)",
                        "type": "new_api_error",
                        "code": "model_not_found"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Any other failure. The wrapper is the same everywhere. Read error.code, not the status code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/models": {
      "get": {
        "operationId": "listModels",
        "tags": [
          "OpenAI protocol"
        ],
        "summary": "List available models",
        "description": "The authoritative catalog — 15 models at the 2026-09-21 snapshot. Resolve a model ID against this endpoint rather than against the enum in this document, which is only as fresh as the last build.\n\nGET /v1/models costs nothing and uses the same key. A 200 with a model list proves the key, the network and the CDN edge are all fine — which means the problem is in your request body, not your credentials.",
        "responses": {
          "200": {
            "description": "The catalog. Every entry’s `id` is what goes in the `model` field of the two POST endpoints.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelList"
                }
              }
            }
          },
          "401": {
            "description": "The official SDKs do not retry this status; it surfaces on the first attempt.\n\n- `error.code`: empty string (Measured on the live endpoint) — The key does not exist, was revoked, or the Authorization header is missing altogether. Confirm the key still exists on the API Keys page in the console, or create a new one. One thing this is not: a missing \"Bearer \" prefix — the gateway accepts the bare key too, so that is never the cause. Message returned: `Invalid token`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "invalid-key": {
                    "summary": "new_api_error",
                    "value": {
                      "error": {
                        "message": "Invalid token",
                        "type": "new_api_error",
                        "code": ""
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Any other failure. The wrapper is the same everywhere. Read error.code, not the status code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A key created in the console. The gateway also accepts the bare key with no `Bearer ` prefix, so a missing prefix is never the cause of a 401."
      },
      "anthropicApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "The same key, in the header the Anthropic SDKs send. Used by `POST /messages`."
      }
    },
    "schemas": {
      "ModelId": {
        "type": "string",
        "enum": [
          "deepseek/deepseek-v4-flash",
          "deepseek/deepseek-v4-pro",
          "deepseek/deepseek-v4.1-flash",
          "deepseek/deepseek-v4-flash-0731",
          "z-ai/glm-5.2",
          "z-ai/glm-5.3",
          "z-ai/glm-5.3-flash",
          "moonshotai/kimi-k3",
          "moonshotai/kimi-k2.6",
          "tencent/hy3",
          "xiaomi/mimo-v2.5",
          "openai/gpt-6-astra",
          "openai/gpt-5.6-sol",
          "openai/gpt-5.6-terra",
          "openai/gpt-5.6-luna"
        ],
        "examples": [
          "deepseek/deepseek-v4-flash"
        ],
        "description": "Model IDs are always `vendor/model`. This enum is a build-time snapshot of the catalog, synced 2026-09-21; `GET /models` is the authoritative list at any moment. An ID that is not in the catalog fails with HTTP 503, not 404 — see the 503 response below before writing a retry loop."
      },
      "ChatContentPart": {
        "description": "One part of a multi-part user message. Image parts are accepted by the gateway but no model in this catalog actually reads them — see \"Images are accepted, then ignored\" at https://y-api.bestvirtualgoods.com/docs/errors. Treat this API as text-only.",
        "oneOf": [
          {
            "type": "object",
            "required": [
              "type",
              "text"
            ],
            "properties": {
              "type": {
                "const": "text"
              },
              "text": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "image_url"
            ],
            "properties": {
              "type": {
                "const": "image_url"
              },
              "image_url": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "A `data:` URL or an https URL. Both are accepted; neither reaches a model that can see."
                  }
                }
              }
            }
          }
        ]
      },
      "ChatMessage": {
        "type": "object",
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "system",
              "user",
              "assistant",
              "tool"
            ]
          },
          "content": {
            "description": "A plain string, or an array of parts. Null on an assistant message that only carries `tool_calls`.",
            "oneOf": [
              {
                "type": [
                  "string",
                  "null"
                ]
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ChatContentPart"
                }
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "tool_calls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ToolCall"
            }
          },
          "tool_call_id": {
            "type": "string",
            "description": "Required on a `role: \"tool\"` message: the id of the call it answers."
          }
        }
      },
      "Tool": {
        "type": "object",
        "required": [
          "type",
          "function"
        ],
        "properties": {
          "type": {
            "const": "function"
          },
          "function": {
            "type": "object",
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "parameters": {
                "type": "object",
                "description": "JSON Schema for the arguments.",
                "additionalProperties": true
              }
            }
          }
        }
      },
      "ToolCall": {
        "type": "object",
        "required": [
          "id",
          "function"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Send this back as `tool_call_id` on the answering message."
          },
          "type": {
            "const": "function"
          },
          "function": {
            "type": "object",
            "required": [
              "name",
              "arguments"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "arguments": {
                "type": "string",
                "description": "A JSON document as a string — parse it, do not use it directly."
              }
            }
          }
        }
      },
      "ChatCompletionRequest": {
        "type": "object",
        "required": [
          "model",
          "messages"
        ],
        "additionalProperties": true,
        "properties": {
          "model": {
            "$ref": "#/components/schemas/ModelId"
          },
          "messages": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            },
            "description": "Absent or empty, this fails with HTTP 500 (not 400) and the message names the field."
          },
          "stream": {
            "type": "boolean",
            "default": false,
            "description": "When true the response is `text/event-stream` in OpenAI’s frame format, terminated by `data: [DONE]`."
          },
          "stream_options": {
            "type": "object",
            "properties": {
              "include_usage": {
                "type": "boolean",
                "description": "Adds a final frame carrying `usage`. Verified present, so per-request cost can be computed from the stream."
              }
            }
          },
          "tools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tool"
            }
          },
          "tool_choice": {
            "description": "`\"auto\"`, `\"none\"`, or a specific function.",
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "auto",
                  "none",
                  "required"
                ]
              },
              {
                "type": "object",
                "additionalProperties": true
              }
            ]
          },
          "response_format": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "text",
                  "json_object"
                ]
              }
            },
            "description": "`json_object` is accepted and the body comes back as valid JSON."
          },
          "max_tokens": {
            "type": "integer",
            "minimum": 1
          },
          "max_completion_tokens": {
            "type": "integer",
            "minimum": 1,
            "description": "Caps the text, not the bill: one model billed 21.8× this value because reasoning tokens are billed but never appear in `content` (https://y-api.bestvirtualgoods.com/docs/errors). Do not derive a cost ceiling from it."
          }
        }
      },
      "Usage": {
        "type": "object",
        "required": [
          "prompt_tokens",
          "completion_tokens",
          "total_tokens"
        ],
        "properties": {
          "prompt_tokens": {
            "type": "integer"
          },
          "completion_tokens": {
            "type": "integer",
            "description": "Includes reasoning tokens, which are billed but absent from `content`. This is the number you are charged for."
          },
          "total_tokens": {
            "type": "integer"
          }
        }
      },
      "ChatCompletionResponse": {
        "type": "object",
        "required": [
          "choices",
          "usage"
        ],
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "type": "string"
          },
          "created": {
            "type": "integer"
          },
          "model": {
            "type": "string"
          },
          "choices": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": [
                "message",
                "finish_reason"
              ],
              "properties": {
                "index": {
                  "type": "integer"
                },
                "message": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string"
                    },
                    "content": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "tool_calls": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ToolCall"
                      }
                    },
                    "reasoning_content": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Non-standard extra field on the DeepSeek models. Every mainstream SDK ignores it; it is documented here only so it is not mistaken for a protocol violation."
                    }
                  }
                },
                "finish_reason": {
                  "type": "string",
                  "examples": [
                    "stop",
                    "length",
                    "tool_calls"
                  ]
                }
              }
            }
          },
          "usage": {
            "$ref": "#/components/schemas/Usage"
          }
        }
      },
      "Model": {
        "type": "object",
        "required": [
          "id",
          "object"
        ],
        "additionalProperties": true,
        "properties": {
          "id": {
            "$ref": "#/components/schemas/ModelId"
          },
          "object": {
            "const": "model"
          }
        }
      },
      "ModelList": {
        "type": "object",
        "required": [
          "data"
        ],
        "description": "Note the deviation: the top-level `\"object\": \"list\"` field of the OpenAI spec is absent here. A client that asserts on it will reject an otherwise valid response.",
        "properties": {
          "data": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Model"
            }
          }
        }
      },
      "AnthropicMessage": {
        "type": "object",
        "required": [
          "role",
          "content"
        ],
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "user",
              "assistant"
            ]
          },
          "content": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                },
                "description": "Content blocks. Only `text` and `tool_use` / `tool_result` blocks are covered by the compatibility matrix; image blocks were never probed on this endpoint."
              }
            ]
          }
        }
      },
      "AnthropicTool": {
        "type": "object",
        "required": [
          "name",
          "input_schema"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "input_schema": {
            "type": "object",
            "description": "JSON Schema for the tool input.",
            "additionalProperties": true
          }
        }
      },
      "AnthropicMessagesRequest": {
        "type": "object",
        "required": [
          "model",
          "max_tokens",
          "messages"
        ],
        "additionalProperties": true,
        "properties": {
          "model": {
            "$ref": "#/components/schemas/ModelId"
          },
          "max_tokens": {
            "type": "integer",
            "minimum": 1,
            "description": "Required by this protocol, unlike `/chat/completions`."
          },
          "messages": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/AnthropicMessage"
            }
          },
          "system": {
            "type": "string",
            "description": "A top-level parameter here, not a message with `role: \"system\"`."
          },
          "tools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AnthropicTool"
            }
          },
          "stream": {
            "type": "boolean",
            "default": false,
            "description": "When true the response is a named SSE event sequence: `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta`, `message_stop`. All six are emitted."
          }
        }
      },
      "AnthropicContentBlock": {
        "description": "A text block or a tool call.",
        "oneOf": [
          {
            "type": "object",
            "required": [
              "type",
              "text"
            ],
            "properties": {
              "type": {
                "const": "text"
              },
              "text": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "id",
              "name",
              "input"
            ],
            "properties": {
              "type": {
                "const": "tool_use"
              },
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "input": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        ]
      },
      "AnthropicUsage": {
        "type": "object",
        "required": [
          "input_tokens",
          "output_tokens"
        ],
        "properties": {
          "input_tokens": {
            "type": "integer"
          },
          "output_tokens": {
            "type": "integer"
          }
        }
      },
      "AnthropicMessageResponse": {
        "type": "object",
        "required": [
          "id",
          "type",
          "content",
          "stop_reason",
          "usage"
        ],
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string",
            "description": "A bare hex string with **no** `msg_` prefix, unlike the official API. Code that asserts on that prefix, or parses the id to route a response, will not match (https://y-api.bestvirtualgoods.com/docs/errors)."
          },
          "type": {
            "const": "message"
          },
          "role": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "content": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AnthropicContentBlock"
            }
          },
          "stop_reason": {
            "type": "string",
            "examples": [
              "end_turn",
              "max_tokens",
              "tool_use"
            ]
          },
          "usage": {
            "$ref": "#/components/schemas/AnthropicUsage"
          }
        }
      },
      "ApiError": {
        "type": "object",
        "required": [
          "error"
        ],
        "description": "The wrapper is always {\"error\": {...}}, but the field set is not stable: some errors carry param, others omit it, and code is frequently an empty string. Parse defensively — treat every field as optional. Every message ends with a request id, and it differs on every call. Strip it before comparing messages against this page — and include it when you report a problem, because it is what identifies your exact request in the logs.",
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": true,
            "properties": {
              "message": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "code": {
                "type": "string",
                "description": "The real reason lives here, not in the status code. Frequently an empty string."
              },
              "param": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}
