{
  "openapi": "3.1.0",
  "info": {
    "title": "altrouter API",
    "version": "1.0.0",
    "description": "OpenAI-compatible gateway. Point any OpenAI SDK at the base URL below with your altrouter key (ar-…) — no other change needed. One key, one balance, every model."
  },
  "servers": [
    {
      "url": "https://api.altrouter.ai/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Chat",
      "description": "Text & multimodal chat completions."
    },
    {
      "name": "Images",
      "description": "Image generation and editing."
    },
    {
      "name": "Videos",
      "description": "Video generation — asynchronous: create, then poll."
    },
    {
      "name": "Catalog",
      "description": "Models and account balance."
    }
  ],
  "paths": {
    "/chat/completions": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Create a chat completion",
        "description": "OpenAI-compatible chat completions, with optional SSE streaming and tool calling.",
        "operationId": "createChatCompletion",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "A model id from the catalog, e.g. \"gpt-5.4\". See GET /v1/models.",
                    "enum": [
                      "gemini-3.1-flash-lite",
                      "gemini-2.5-flash",
                      "gemini-3-flash",
                      "gemini-3.5-flash",
                      "gemini-2.5-pro",
                      "gemini-3.1-pro",
                      "gemini-3-pro",
                      "gpt-5.4",
                      "gpt-5.5",
                      "gpt-5.2",
                      "gpt-5.6",
                      "gpt-5.6-pro",
                      "gpt-5.6-mini",
                      "claude-haiku-4-5",
                      "claude-sonnet-4-5",
                      "claude-opus-4-5",
                      "claude-opus-4-8",
                      "claude-opus-4-7",
                      "claude-sonnet-4-6",
                      "claude-sonnet-5",
                      "claude-opus-4-6",
                      "claude-fable-5",
                      "grok-4.5",
                      "grok-4.3"
                    ]
                  },
                  "messages": {
                    "type": "array",
                    "items": {},
                    "description": "The conversation: an array of messages with roles system / user / assistant / tool. Supports multimodal content (text + image_url)."
                  },
                  "stream": {
                    "type": "boolean",
                    "description": "If true, the reply streams as OpenAI-compatible server-sent events (SSE). The stream ends with data: [DONE]."
                  },
                  "max_tokens": {
                    "type": "integer",
                    "description": "Maximum tokens to generate. The alias max_completion_tokens is also accepted. Defaults to a server-side cap."
                  },
                  "temperature": {
                    "type": "number",
                    "description": "Sampling randomness. Higher is more creative, lower is more deterministic."
                  },
                  "top_p": {
                    "type": "number",
                    "description": "Nucleus sampling — the probability mass to sample tokens from."
                  },
                  "stop": {
                    "type": "array",
                    "items": {},
                    "description": "A string or array of strings at which generation stops."
                  },
                  "tools": {
                    "type": "array",
                    "items": {},
                    "description": "Function-calling tool definitions in OpenAI format."
                  },
                  "tool_choice": {
                    "type": "object",
                    "description": "Controls tool use: auto / required / none / a specific function."
                  },
                  "reasoning_effort": {
                    "type": "string",
                    "description": "Thinking budget for reasoning models. Reasoning content is returned in message.reasoning_content."
                  },
                  "response_format": {
                    "type": "object",
                    "description": "Structured output: { \"type\": \"json_object\" } or { \"type\": \"json_schema\", \"json_schema\": … }. See the Structured outputs guide."
                  },
                  "web_search": {
                    "type": "boolean",
                    "description": "Server-side web search: the model answers with live data from the web."
                  },
                  "seed": {
                    "type": "integer",
                    "description": "Seed for reproducible sampling where the model supports it."
                  },
                  "frequency_penalty": {
                    "type": "number",
                    "description": "Penalizes tokens by their existing frequency."
                  },
                  "presence_penalty": {
                    "type": "number",
                    "description": "Penalizes tokens that have already appeared."
                  }
                },
                "required": [
                  "model",
                  "messages"
                ]
              },
              "example": {
                "model": "gemini-3.1-flash-lite",
                "messages": [
                  {
                    "role": "user",
                    "content": "Hello!"
                  }
                ],
                "stream": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A chat completion (or an SSE stream when stream=true).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletion"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits, or the key’s spending cap is exhausted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The surface is outside the key’s scopes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Model not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal gateway error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Model-side error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The model is temporarily unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "Request exceeded the allowed time.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/images/generations": {
      "post": {
        "tags": [
          "Images"
        ],
        "summary": "Create an image",
        "description": "Generate or edit an image. Results are re-hosted on our CDN and returned as URLs.",
        "operationId": "createImage",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "An image model id from the catalog, e.g. \"nano-banana-pro\".",
                    "enum": [
                      "nano-banana-fast",
                      "nano-banana",
                      "nano-banana-2",
                      "nano-banana-pro",
                      "gpt-image-2",
                      "seedream-v4",
                      "flux-2-pro",
                      "qwen-image",
                      "z-image",
                      "seedream-4.5",
                      "seedream-5-lite",
                      "seedream-5-pro",
                      "grok-imagine",
                      "wan-2.7"
                    ]
                  },
                  "prompt": {
                    "type": "string",
                    "description": "A text description of the desired image."
                  },
                  "image": {
                    "type": "array",
                    "items": {},
                    "description": "Reference images (URL or base64) for editing. The router picks the model’s edit variant automatically."
                  },
                  "resolution": {
                    "type": "string",
                    "description": "Resolution tier — selects the model variant and price (quality:\"hd\" ⇒ 4K)."
                  },
                  "response_format": {
                    "type": "string",
                    "description": "Result shape. Defaults to url: the image is re-hosted on our CDN and the link is permanent."
                  }
                },
                "required": [
                  "model",
                  "prompt"
                ]
              },
              "example": {
                "model": "nano-banana-fast",
                "prompt": "A red panda coding at a laptop, studio lighting"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The generated image(s).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or content moderation rejection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits, or the key’s spending cap is exhausted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The surface is outside the key’s scopes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Model not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal gateway error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Model-side error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The model is temporarily unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "Request exceeded the allowed time.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/videos": {
      "post": {
        "tags": [
          "Videos"
        ],
        "summary": "Create a video",
        "description": "Starts a render and returns immediately with a `video` object in `queued`. A render takes minutes, so poll `GET /videos/{id}` until `status` is `completed` (the re-hosted mp4 arrives in `url`) or `failed`. Credit is reserved at create time and charged only on a completed render.",
        "operationId": "createVideo",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "A video model id from the catalog, e.g. \"veo-3.1-fast\".",
                    "enum": [
                      "veo-3.1",
                      "veo-3.1-fast",
                      "seedance-2.0",
                      "kling-3.0",
                      "kling-2.6",
                      "hailuo-2.3",
                      "wan-2.7-video"
                    ]
                  },
                  "prompt": {
                    "type": "string",
                    "description": "A text description of the scene."
                  },
                  "seconds": {
                    "type": "integer",
                    "description": "Clip length in seconds. The allowed values are the model’s own (see its page); out-of-range values are clamped. `duration` is accepted as an alias."
                  },
                  "image": {
                    "type": "array",
                    "items": {},
                    "description": "A reference frame (URL or base64) — its presence routes the request to the model’s image-to-video variant. `input_reference` is accepted for a single frame."
                  }
                },
                "required": [
                  "model",
                  "prompt"
                ]
              },
              "example": {
                "model": "veo-3.1",
                "prompt": "A red panda skateboarding through neon-lit Tokyo streets at night",
                "seconds": 8
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The render was accepted and queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Video"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or content moderation rejection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits, or the key’s spending cap is exhausted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The surface is outside the key’s scopes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Model not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal gateway error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Model-side error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The model is temporarily unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "Request exceeded the allowed time.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Videos"
        ],
        "summary": "List videos",
        "description": "The most recent renders for the org that owns the API key, newest first.",
        "operationId": "listVideos",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The video list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Video"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/videos/{id}": {
      "get": {
        "tags": [
          "Videos"
        ],
        "summary": "Retrieve a video",
        "description": "The current state of one render. Poll this until `status` is `completed` or `failed`.",
        "operationId": "retrieveVideo",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The video.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Video"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such video.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/videos/{id}/content": {
      "get": {
        "tags": [
          "Videos"
        ],
        "summary": "Download the video",
        "description": "Redirects (302) to the re-hosted mp4 once the render is `completed`. The same URL is in the video object’s `url`.",
        "operationId": "downloadVideo",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to the mp4."
          },
          "400": {
            "description": "The render has not completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such video.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/models": {
      "get": {
        "tags": [
          "Catalog"
        ],
        "summary": "List models",
        "description": "The catalog of callable models, with per-model pricing (USD) and tunable params. Takes no query parameters.",
        "operationId": "listModels",
        "responses": {
          "200": {
            "description": "The model list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "gemini-3.1-flash-lite",
                      "object": "model",
                      "created": 1735689600,
                      "owned_by": "altrouter",
                      "surface": "chat",
                      "context_length": 200000,
                      "pricing": {
                        "prompt_per_1m_usd": 1,
                        "completion_per_1m_usd": 4,
                        "approximate": false
                      },
                      "params": [
                        {
                          "key": "temperature",
                          "type": "slider",
                          "min": 0,
                          "max": 2,
                          "step": 0.1,
                          "default": 1
                        },
                        {
                          "key": "max_tokens",
                          "type": "number",
                          "min": 1,
                          "max": 32000
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/credits": {
      "get": {
        "tags": [
          "Catalog"
        ],
        "summary": "Get credit balance",
        "description": "The remaining balance for the org that owns the API key. Takes no query parameters.",
        "operationId": "getCredits",
        "responses": {
          "200": {
            "description": "The current balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Credits"
                },
                "example": {
                  "object": "credits",
                  "available_usd": 42.5,
                  "balance_usd": 50,
                  "held_usd": 7.5
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your altrouter key, e.g. `Authorization: Bearer ar-…`."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "invalid_request_error",
                  "authentication_error",
                  "permission_error",
                  "not_found_error",
                  "rate_limit_error",
                  "insufficient_quota",
                  "content_policy_violation",
                  "api_error",
                  "service_unavailable"
                ]
              },
              "param": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "code": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "message",
              "type"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "ChatCompletion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "type": "string",
            "const": "chat.completion"
          },
          "created": {
            "type": "integer"
          },
          "model": {
            "type": "string"
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer"
                },
                "message": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string"
                    },
                    "content": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "reasoning_content": {
                      "type": "string"
                    },
                    "tool_calls": {
                      "type": "array",
                      "items": {}
                    }
                  }
                },
                "finish_reason": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "usage": {
            "$ref": "#/components/schemas/Usage"
          }
        }
      },
      "ImageResponse": {
        "type": "object",
        "properties": {
          "created": {
            "type": "integer"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                },
                "b64_json": {
                  "type": "string"
                },
                "revised_prompt": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Video": {
        "type": "object",
        "description": "One render. Asynchronous: poll until `status` is `completed` or `failed`.",
        "properties": {
          "id": {
            "type": "string",
            "description": "vid_… — pass it to GET /videos/{id}."
          },
          "object": {
            "type": "string",
            "const": "video"
          },
          "model": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "in_progress",
              "completed",
              "failed"
            ]
          },
          "created_at": {
            "type": "integer",
            "description": "Unix timestamp (seconds)."
          },
          "completed_at": {
            "type": "integer"
          },
          "seconds": {
            "type": "integer",
            "description": "The clip length this render was priced on."
          },
          "url": {
            "type": "string",
            "description": "The re-hosted mp4 — present once completed."
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                }
              }
            }
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        },
        "required": [
          "id",
          "object",
          "model",
          "status",
          "created_at"
        ]
      },
      "Usage": {
        "type": "object",
        "properties": {
          "prompt_tokens": {
            "type": "integer"
          },
          "completion_tokens": {
            "type": "integer"
          },
          "total_tokens": {
            "type": "integer"
          }
        }
      },
      "ModelList": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Model"
            }
          }
        }
      },
      "Model": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "type": "string",
            "const": "model"
          },
          "created": {
            "type": "integer",
            "description": "Unix timestamp (seconds)."
          },
          "owned_by": {
            "type": "string",
            "const": "altrouter"
          },
          "surface": {
            "type": "string",
            "enum": [
              "chat",
              "image",
              "video"
            ]
          },
          "context_length": {
            "type": "integer",
            "description": "Max context window in tokens (chat models)."
          },
          "pricing": {
            "description": "Our sell price, in USD — ChatPricing, ImagePricing or VideoPricing, per the model’s surface.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ChatPricing"
              },
              {
                "$ref": "#/components/schemas/ImagePricing"
              },
              {
                "$ref": "#/components/schemas/VideoPricing"
              }
            ]
          },
          "params": {
            "type": "array",
            "description": "Tunable request parameters this model accepts.",
            "items": {
              "$ref": "#/components/schemas/ParamField"
            }
          }
        },
        "required": [
          "id",
          "object",
          "created",
          "owned_by",
          "surface",
          "pricing",
          "params"
        ]
      },
      "ChatPricing": {
        "type": "object",
        "description": "Sell price for a chat model, USD per 1M tokens.",
        "properties": {
          "prompt_per_1m_usd": {
            "type": "number"
          },
          "completion_per_1m_usd": {
            "type": "number"
          },
          "approximate": {
            "type": "boolean",
            "description": "True when the price is a pre-flight estimate (billed on actual usage)."
          },
          "discount_pct": {
            "type": "integer",
            "description": "Savings vs the official list price, when we are cheaper."
          },
          "official_prompt_per_1m_usd": {
            "type": "number"
          },
          "official_completion_per_1m_usd": {
            "type": "number"
          }
        },
        "required": [
          "prompt_per_1m_usd",
          "completion_per_1m_usd",
          "approximate"
        ]
      },
      "ImagePricing": {
        "type": "object",
        "description": "Sell price for an image model, USD per image.",
        "properties": {
          "per_image_usd": {
            "type": "number"
          },
          "per_image_4k_usd": {
            "type": "number",
            "description": "Price for the cheapest 4K-capable variant, when offered."
          },
          "approximate": {
            "type": "boolean"
          },
          "discount_pct": {
            "type": "integer"
          },
          "official_per_image_usd": {
            "type": "number"
          }
        },
        "required": [
          "per_image_usd",
          "approximate"
        ]
      },
      "VideoPricing": {
        "type": "object",
        "description": "Sell price for a video model. Length-priced models quote per second; models the upstream charges flat per clip quote per video.",
        "properties": {
          "per_second_usd": {
            "type": "number"
          },
          "per_video_usd": {
            "type": "number"
          },
          "approximate": {
            "type": "boolean"
          },
          "discount_pct": {
            "type": "integer"
          },
          "official_per_second_usd": {
            "type": "number"
          },
          "official_per_video_usd": {
            "type": "number"
          }
        },
        "required": [
          "approximate"
        ]
      },
      "ParamField": {
        "type": "object",
        "description": "A tunable request parameter for a model (rendered as a control in the playground).",
        "properties": {
          "key": {
            "type": "string",
            "description": "The literal request field name."
          },
          "type": {
            "type": "string",
            "enum": [
              "slider",
              "number",
              "boolean",
              "select",
              "image",
              "text"
            ]
          },
          "default": {
            "type": [
              "number",
              "string",
              "boolean"
            ]
          },
          "min": {
            "type": "number"
          },
          "max": {
            "type": "number"
          },
          "step": {
            "type": "number"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "key",
          "type"
        ]
      },
      "Credits": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "credits"
          },
          "available_usd": {
            "type": "number",
            "description": "Spendable balance (settled balance minus active holds), USD."
          },
          "balance_usd": {
            "type": "number",
            "description": "Total settled balance, USD."
          },
          "held_usd": {
            "type": "number",
            "description": "Funds reserved by in-flight requests, USD."
          }
        },
        "required": [
          "object",
          "available_usd",
          "balance_usd",
          "held_usd"
        ]
      }
    }
  }
}
