{
  "openapi": "3.1.0",
  "info": {
    "title": "AIOOS Public API",
    "version": "1.0.0",
    "summary": "Mint a single-use realtime session for the AIOOS voice agent.",
    "description": "This specification describes the publicly documented AIOOS API surface. It is derived verbatim from the developer documentation at https://aioos.ai/docs/ and describes only endpoints that are already public there.\n\nThe API is intentionally small: you exchange an agent key for a short-lived realtime session, then speak to the agent over the returned WebSocket. Everything else — the agent's knowledge, voice and behaviour — is configured in the AIOOS console, not through this API.",
    "contact": {
      "name": "AIOOS Developer Docs",
      "url": "https://aioos.ai/docs/"
    }
  },
  "servers": [
    {
      "url": "https://aioos.ai",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Realtime",
      "description": "Session minting for browser and server clients."
    }
  ],
  "paths": {
    "/v1/session": {
      "post": {
        "tags": ["Realtime"],
        "operationId": "createSession",
        "summary": "Create a realtime session",
        "description": "Exchanges an agent key for a single-use realtime credential.\n\nThere is no authentication header — the key travels in the request body. CORS is open, so the endpoint is callable from browsers and from servers alike.\n\nRate limits: 10 requests per minute per IP, and 30 requests per minute per key.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SessionRequest" },
              "examples": {
                "browser": {
                  "summary": "From a browser",
                  "description": "Browsers should always send page_origin.",
                  "value": {
                    "key": "wk_example_agent_key",
                    "page_origin": "https://kunde.example.com"
                  }
                },
                "server": {
                  "summary": "From a server",
                  "description": "page_origin may be omitted while the key carries no origin allowlist.",
                  "value": { "key": "wk_example_agent_key" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session created.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SessionResponse" },
                "example": {
                  "token": "single-use-session-token",
                  "server_url": "wss://realtime.example/rtc",
                  "ice_servers": null
                }
              }
            }
          },
          "400": {
            "description": "`bad_body` — malformed JSON. `bad_key` — the key is not a valid `wk_…` string.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "bad_key" }
              }
            }
          },
          "402": {
            "description": "`no_minutes` — the plan's minute pool is empty. Upgrade or top up at https://aioos.ai/app.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "no_minutes" }
              }
            }
          },
          "403": {
            "description": "`unknown_key` — the key does not exist or was revoked. `origin_not_allowed` — the key restricts origins and `page_origin` is not on the list.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "origin_not_allowed" }
              }
            }
          },
          "429": {
            "description": "`rate_limited` — 10 requests/min per IP, 30 requests/min per key were exceeded. Back off and retry.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "rate_limited" }
              }
            }
          },
          "500": {
            "description": "Transient server problem. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "internal" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SessionRequest": {
        "type": "object",
        "required": ["key"],
        "additionalProperties": false,
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^wk_",
            "description": "Your agent key (`wk_…`). Agent keys are publishable — they are designed to sit in browser code.",
            "examples": ["wk_example_agent_key"]
          },
          "page_origin": {
            "type": "string",
            "format": "uri",
            "description": "Send `location.origin` from browsers. Required once your key carries an origin allowlist; server-side callers may omit it while the key has no allowlist.",
            "examples": ["https://kunde.example.com"]
          }
        }
      },
      "SessionResponse": {
        "type": "object",
        "required": ["token", "server_url"],
        "properties": {
          "token": {
            "type": "string",
            "description": "Single-use, single-session credential. Do not cache or share it."
          },
          "server_url": {
            "type": "string",
            "description": "WebSocket URL to connect to. Always use the returned value — never hardcode it."
          },
          "ice_servers": {
            "type": ["array", "null"],
            "description": "Short-lived TURN relay credentials for restrictive corporate networks. Pass them to the SDK; when `null`, connect without them.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Machine-readable error code.",
            "enum": [
              "bad_body",
              "bad_key",
              "no_minutes",
              "unknown_key",
              "origin_not_allowed",
              "rate_limited",
              "internal"
            ]
          }
        }
      }
    }
  }
}
