{
  "openapi": "3.1.0",
  "info": {
    "title": "CLAWD Bot API",
    "version": "0.1.0",
    "summary": "Standalone Fly service for CLAWD companion chat, holder portal, OpenAI-compatible gateway, and Telegram webhook.",
    "description": "HTTP surface exposed by `server/standalone.ts` on the clawd-bot Fly app (e.g. https://clawd-bot-8bit.fly.dev).\n\n**Surfaces**\n- Health / service discovery\n- Public free OpenRouter SSE chat + holder Grok SSE chat\n- OpenAI-compatible site gateway (`/v1`)\n- Companion thread persistence\n- Holder portal (wallet challenge, session cookie, gateway keys)\n- Telegram webhook\n\n**Auth models**\n| Scheme | Used by |\n| --- | --- |\n| `GatewayBearer` (`Authorization: Bearer <key>`) | `/v1/*` |\n| `HolderSession` (cookie `clawd_holder_session`) | `/portal/api/me`, `/keys` |\n| `TelegramWebhookSecret` (header `X-Telegram-Bot-Api-Secret-Token`) | `POST /telegram/webhook` |\n\nPublic free chat and companion threads do not require auth on the standalone service. Holder chat requires a verified holder callback when mounted with `isHolder`; on the default standalone mount without that callback, `POST /api/clawd-bot/holder-chat/stream` returns 401.",
    "contact": {
      "name": "CLAWD Bot",
      "url": "https://clawd-bot-8bit.fly.dev"
    },
    "license": {
      "name": "UNLICENSED",
      "url": "https://clawd-bot-8bit.fly.dev"
    }
  },
  "servers": [
    {
      "url": "https://clawd-bot-8bit.fly.dev",
      "description": "Fly production"
    },
    {
      "url": "http://localhost:8080",
      "description": "Local standalone (`npm start`)"
    }
  ],
  "tags": [
    {
      "name": "Health",
      "description": "Liveness and service map"
    },
    {
      "name": "Docs",
      "description": "OpenAPI document and Scalar reference"
    },
    {
      "name": "Chat",
      "description": "Portable free + holder streaming chat"
    },
    {
      "name": "Gateway",
      "description": "OpenAI-compatible site API (bearer gateway key)"
    },
    {
      "name": "Threads",
      "description": "Companion floppy-disk thread store"
    },
    {
      "name": "Portal",
      "description": "Holder wallet auth, sessions, and API keys"
    },
    {
      "name": "Telegram",
      "description": "Bot webhook integration"
    },
    {
      "name": "GoBotNest",
      "description": "Host clawdbot Go OS (go-bot) inside clawd-bot via the nest subsystem"
    }
  ],
  "paths": {
    "/healthz": {
      "get": {
        "tags": [
          "Health"
        ],
        "operationId": "getHealthz",
        "summary": "Liveness probe",
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthOk"
                },
                "example": {
                  "ok": true
                }
              }
            }
          }
        }
      }
    },
    "/service": {
      "get": {
        "tags": [
          "Health"
        ],
        "operationId": "getService",
        "summary": "Service descriptor and endpoint map",
        "responses": {
          "200": {
            "description": "Named service + canonical paths",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceInfo"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "Docs"
        ],
        "operationId": "getOpenApiDocument",
        "summary": "OpenAPI 3 document (JSON)",
        "description": "Stable public URL for Scalar and other OpenAPI clients. No authentication.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.x document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/docs": {
      "get": {
        "tags": [
          "Docs"
        ],
        "operationId": "getScalarDocs",
        "summary": "Scalar API Reference UI",
        "description": "HTML page that loads `/openapi.json` into Scalar.",
        "responses": {
          "200": {
            "description": "Scalar HTML",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/clawd-bot/status": {
      "get": {
        "tags": [
          "Chat"
        ],
        "operationId": "getClawdBotStatus",
        "summary": "Chat backend configuration probe",
        "responses": {
          "200": {
            "description": "Free/holder configuration flags and resolved free model",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClawdBotStatus"
                }
              }
            }
          }
        }
      }
    },
    "/api/clawd-bot/free-chat/stream": {
      "post": {
        "tags": [
          "Chat"
        ],
        "operationId": "postFreeChatStream",
        "summary": "Public free chat (OpenRouter SSE)",
        "description": "Streams OpenRouter chat completions. Model must be `openrouter/free` or end with `:free` when overridden.\n\nResponse is `text/event-stream` (SSE) when upstream succeeds.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FreeChatRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSE stream of chat completion chunks",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "OpenRouter chat/completions SSE: `data: {choices[0].delta.content}` lines ending with `[DONE]`"
                }
              }
            }
          },
          "400": {
            "description": "Missing messages or non-free model override",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "503": {
            "description": "OPENROUTER_API_KEY not configured or upstream failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/api/clawd-bot/holder-chat/stream": {
      "post": {
        "tags": [
          "Chat"
        ],
        "operationId": "postHolderChatStream",
        "summary": "Holder Grok 4.5 chat (xAI Responses SSE)",
        "description": "Requires a verified holder session when the router is created with an `isHolder` callback. Default standalone mount without `isHolder` always returns 401.",
        "security": [
          {
            "HolderSession": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HolderChatRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSE stream from xAI Responses API",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "message required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "401": {
            "description": "Verified holder session required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "503": {
            "description": "XAI_API_KEY not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models": {
      "get": {
        "tags": [
          "Gateway"
        ],
        "operationId": "listGatewayModels",
        "summary": "List gateway models",
        "security": [
          {
            "GatewayBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OpenAI-style model list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIModelList"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                }
              }
            }
          },
          "503": {
            "description": "Gateway authentication unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/chat/completions": {
      "post": {
        "tags": [
          "Gateway"
        ],
        "operationId": "createGatewayChatCompletion",
        "summary": "OpenAI-compatible chat completions",
        "description": "Authenticated with `Authorization: Bearer <CLAWD_BOT_GATEWAY_KEY or issued holder key>`. Proxies to OpenRouter free models. Supports `stream: true` (SSE) and non-streaming JSON.",
        "security": [
          {
            "GatewayBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GatewayChatRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Chat completion (JSON) or SSE when stream=true",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIChatCompletion"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "messages required or invalid free model",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream model failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                }
              }
            }
          },
          "503": {
            "description": "Gateway authentication unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                }
              }
            }
          }
        }
      },
      "options": {
        "tags": [
          "Gateway"
        ],
        "operationId": "optionsGatewayChatCompletion",
        "summary": "CORS preflight for chat completions",
        "description": "Returns 204 when Origin is listed in `CLAWD_BOT_SITE_ORIGINS`.",
        "responses": {
          "204": {
            "description": "CORS preflight allowed"
          }
        }
      }
    },
    "/api/clawd-bot/threads/threads": {
      "get": {
        "tags": [
          "Threads"
        ],
        "operationId": "listCompanionThreads",
        "summary": "List companion threads for a wallet scope",
        "parameters": [
          {
            "name": "wallet",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address; empty scopes to `anon`"
          }
        ],
        "responses": {
          "200": {
            "description": "Thread summaries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Threads"
        ],
        "operationId": "upsertCompanionThread",
        "summary": "Create or replace a companion thread",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanionThread"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Persisted thread",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadUpsertResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid thread payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/api/clawd-bot/threads/threads/{id}": {
      "get": {
        "tags": [
          "Threads"
        ],
        "operationId": "getCompanionThread",
        "summary": "Load a companion thread",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 4,
              "maxLength": 80
            }
          },
          {
            "name": "wallet",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full thread",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadGetResponse"
                }
              }
            }
          },
          "404": {
            "description": "Thread not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Threads"
        ],
        "operationId": "deleteCompanionThread",
        "summary": "Delete a companion thread",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "wallet",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkTrue"
                }
              }
            }
          },
          "404": {
            "description": "Thread not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/portal/api/config": {
      "get": {
        "tags": [
          "Portal"
        ],
        "operationId": "getPortalConfig",
        "summary": "Holder gate configuration",
        "responses": {
          "200": {
            "description": "Mint, minimum balance, gateway base path",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalConfig"
                }
              }
            }
          }
        }
      }
    },
    "/portal/api/readiness": {
      "get": {
        "tags": [
          "Portal"
        ],
        "operationId": "getPortalReadiness",
        "summary": "Neon + Convex readiness",
        "responses": {
          "200": {
            "description": "Both backends ready",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalReadiness"
                }
              }
            }
          },
          "503": {
            "description": "One or both backends unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalReadiness"
                }
              }
            }
          }
        }
      }
    },
    "/portal/api/challenge": {
      "post": {
        "tags": [
          "Portal"
        ],
        "operationId": "createPortalChallenge",
        "summary": "Create SIWS-style wallet challenge message",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalChallengeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Human-readable message to sign",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalChallengeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid Solana wallet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/portal/api/verify": {
      "post": {
        "tags": [
          "Portal"
        ],
        "operationId": "verifyPortalChallenge",
        "summary": "Verify signed challenge and set holder session cookie",
        "description": "On success sets HttpOnly cookie `clawd_holder_session` (Secure; SameSite=Lax; 7d).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalVerifyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Holder verified; session cookie set",
            "headers": {
              "Set-Cookie": {
                "description": "clawd_holder_session=...; Path=/; HttpOnly; Secure; SameSite=Lax",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalVerifyResponse"
                }
              }
            }
          },
          "401": {
            "description": "Signature verification failed or challenge expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "403": {
            "description": "Wallet below CLAWD minimum",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalHoldingError"
                }
              }
            }
          },
          "503": {
            "description": "Balance verification unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/portal/api/me": {
      "get": {
        "tags": [
          "Portal"
        ],
        "operationId": "getPortalMe",
        "summary": "Current holder session + keys",
        "security": [
          {
            "HolderSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Holding snapshot and gateway keys",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalMe"
                }
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "503": {
            "description": "Balance verification unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/portal/api/keys": {
      "post": {
        "tags": [
          "Portal"
        ],
        "operationId": "issuePortalKey",
        "summary": "Issue personal gateway API key",
        "description": "Returns the full API key once; store it client-side. Subsequent list calls only show prefixes.",
        "security": [
          {
            "HolderSession": []
          }
        ],
        "responses": {
          "201": {
            "description": "Key issued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalKeyIssueResponse"
                }
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "403": {
            "description": "Holder status no longer active",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "503": {
            "description": "Could not issue key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/portal/api/keys/{id}": {
      "delete": {
        "tags": [
          "Portal"
        ],
        "operationId": "revokePortalKey",
        "summary": "Revoke a gateway API key",
        "security": [
          {
            "HolderSession": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkTrue"
                }
              }
            }
          },
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "404": {
            "description": "Key not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        }
      }
    },
    "/portal/api/logout": {
      "post": {
        "tags": [
          "Portal"
        ],
        "operationId": "portalLogout",
        "summary": "Clear holder session cookie",
        "responses": {
          "200": {
            "description": "Cookie cleared",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkTrue"
                }
              }
            }
          }
        }
      }
    },
    "/telegram/status": {
      "get": {
        "tags": [
          "Telegram"
        ],
        "operationId": "getTelegramStatus",
        "summary": "Telegram integration probe",
        "responses": {
          "200": {
            "description": "Whether bot token + webhook secret are configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TelegramStatus"
                }
              }
            }
          }
        }
      }
    },
    "/telegram/webhook": {
      "post": {
        "tags": [
          "Telegram"
        ],
        "operationId": "postTelegramWebhook",
        "summary": "Telegram Bot API webhook receiver",
        "description": "Requires header `X-Telegram-Bot-Api-Secret-Token` matching `TELEGRAM_WEBHOOK_SECRET`. Responds immediately with `{ok:true}`; message handling runs asynchronously.",
        "security": [
          {
            "TelegramWebhookSecret": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TelegramUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkTrue"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid webhook secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/go-bot/nest": {
      "get": {
        "tags": [
          "GoBotNest"
        ],
        "operationId": "getGoBotNest",
        "summary": "Go-bot nest control plane (inventory + mode)",
        "responses": {
          "200": {
            "description": "Nest status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "ok": true,
                  "name": "go-bot-nest",
                  "mode": "guest"
                }
              }
            }
          }
        }
      }
    },
    "/go-bot/api/status": {
      "get": {
        "tags": [
          "GoBotNest"
        ],
        "operationId": "getGoBotNestStatus",
        "summary": "Nested go-bot guest/live status",
        "responses": {
          "200": {
            "description": "Status payload",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/go-bot/api/packages": {
      "get": {
        "tags": [
          "GoBotNest"
        ],
        "operationId": "getGoBotNestPackages",
        "summary": "List go-bot pkg/* packages from nested tree",
        "responses": {
          "200": {
            "description": "Package inventory",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/go-bot/api/health": {
      "get": {
        "tags": [
          "GoBotNest"
        ],
        "operationId": "getGoBotNestHealth",
        "summary": "Nest health",
        "responses": {
          "200": {
            "description": "Health",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "GatewayBearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "CLAWD gateway key",
        "description": "Admin `CLAWD_BOT_GATEWAY_KEY` or a personal key issued via `POST /portal/api/keys`. Sent as `Authorization: Bearer <key>`."
      },
      "HolderSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "clawd_holder_session",
        "description": "HttpOnly session cookie set by `POST /portal/api/verify` after wallet signature verification. Used by `/portal/api/me` and key management."
      },
      "TelegramWebhookSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Telegram-Bot-Api-Secret-Token",
        "description": "Must equal `TELEGRAM_WEBHOOK_SECRET` configured on the server and registered with Telegram `setWebhook`."
      }
    },
    "schemas": {
      "HealthOk": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "OkTrue": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "ErrorMessage": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "GatewayError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              }
            },
            "required": [
              "message"
            ]
          }
        }
      },
      "ServiceInfo": {
        "type": "object",
        "required": [
          "name",
          "ok",
          "endpoints"
        ],
        "properties": {
          "name": {
            "type": "string",
            "example": "clawd-bot"
          },
          "ok": {
            "type": "boolean"
          },
          "endpoints": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "status": "/api/clawd-bot/status",
              "freeChat": "/api/clawd-bot/free-chat/stream",
              "threads": "/api/clawd-bot/threads/threads",
              "gateway": "/v1/chat/completions",
              "telegram": "/telegram/status"
            }
          }
        }
      },
      "ClawdBotStatus": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "freeConfigured": {
            "type": "boolean"
          },
          "freeModel": {
            "type": "string"
          },
          "freeRouter": {
            "type": "boolean"
          },
          "freeEndpoint": {
            "type": "string",
            "format": "uri"
          },
          "holderConfigured": {
            "type": "boolean"
          },
          "custodySigning": {
            "type": "boolean"
          }
        }
      },
      "ChatMessage": {
        "type": "object",
        "required": [
          "role",
          "content"
        ],
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "system",
              "user",
              "assistant"
            ]
          },
          "content": {
            "type": "string"
          },
          "reasoning_details": {
            "description": "Optional OpenRouter multi-turn reasoning continuity field",
            "nullable": true
          }
        }
      },
      "FreeChatRequest": {
        "type": "object",
        "required": [
          "messages"
        ],
        "properties": {
          "messages": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            }
          },
          "model": {
            "type": "string",
            "description": "Free-only override: `openrouter/free` or `*:free`",
            "example": "openrouter/free"
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2,
            "default": 0.6
          },
          "max_tokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 4096,
            "default": 700
          },
          "reasoning": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional OpenRouter reasoning map for supported models"
          }
        }
      },
      "HolderChatRequest": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "previous_response_id": {
            "type": "string",
            "description": "xAI Responses API chain id from a prior turn"
          }
        }
      },
      "GatewayChatRequest": {
        "type": "object",
        "required": [
          "messages"
        ],
        "properties": {
          "messages": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            }
          },
          "model": {
            "type": "string",
            "description": "Free model id only (`openrouter/free` or `*:free`)"
          },
          "stream": {
            "type": "boolean",
            "default": false
          },
          "temperature": {
            "type": "number"
          },
          "max_tokens": {
            "type": "integer"
          }
        }
      },
      "OpenAIModelList": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "object": {
                  "type": "string",
                  "const": "model"
                },
                "owned_by": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "OpenAIChatCompletion": {
        "type": "object",
        "description": "OpenAI-compatible chat completion object (shape depends on upstream OpenRouter)",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "type": "string"
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "CompanionThreadMessage": {
        "type": "object",
        "required": [
          "role",
          "content"
        ],
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "user",
              "assistant"
            ]
          },
          "content": {
            "type": "string"
          }
        }
      },
      "CompanionThread": {
        "type": "object",
        "required": [
          "id",
          "title",
          "messages",
          "mode"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 4,
            "maxLength": 80
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "messages": {
            "type": "array",
            "maxItems": 200,
            "items": {
              "$ref": "#/components/schemas/CompanionThreadMessage"
            }
          },
          "lastResponseId": {
            "type": "string",
            "nullable": true
          },
          "model": {
            "type": "string"
          },
          "mode": {
            "type": "string",
            "enum": [
              "holder",
              "public"
            ]
          },
          "walletAddress": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "number"
          },
          "updatedAt": {
            "type": "number"
          }
        }
      },
      "ThreadListResponse": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "model": {
                  "type": "string"
                },
                "mode": {
                  "type": "string"
                },
                "messageCount": {
                  "type": "integer"
                },
                "lastResponseId": {
                  "type": "string",
                  "nullable": true
                },
                "updatedAt": {
                  "type": "number"
                },
                "createdAt": {
                  "type": "number"
                }
              }
            }
          }
        }
      },
      "ThreadGetResponse": {
        "type": "object",
        "required": [
          "thread"
        ],
        "properties": {
          "thread": {
            "$ref": "#/components/schemas/CompanionThread"
          }
        }
      },
      "ThreadUpsertResponse": {
        "type": "object",
        "required": [
          "ok",
          "thread"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "thread": {
            "$ref": "#/components/schemas/CompanionThread"
          }
        }
      },
      "PortalConfig": {
        "type": "object",
        "properties": {
          "mint": {
            "type": "string",
            "description": "CLAWD mint address"
          },
          "minimum": {
            "type": "number",
            "description": "Minimum UI token balance"
          },
          "gatewayUrl": {
            "type": "string",
            "example": "/v1"
          }
        }
      },
      "PortalReadiness": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "neon": {
            "type": "boolean"
          },
          "convex": {
            "type": "boolean"
          }
        }
      },
      "PortalChallengeRequest": {
        "type": "object",
        "required": [
          "wallet"
        ],
        "properties": {
          "wallet": {
            "type": "string",
            "description": "Base58 Solana wallet address (32-byte decoded length)"
          }
        }
      },
      "PortalChallengeResponse": {
        "type": "object",
        "required": [
          "message",
          "expiresAt"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "UTF-8 message the wallet must sign"
          },
          "expiresAt": {
            "type": "number",
            "description": "Unix ms expiry"
          }
        }
      },
      "PortalVerifyRequest": {
        "type": "object",
        "required": [
          "wallet",
          "message",
          "signature"
        ],
        "properties": {
          "wallet": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "signature": {
            "type": "string",
            "description": "Base58-encoded ed25519 signature of `message`"
          }
        }
      },
      "PortalVerifyResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "wallet": {
            "type": "string"
          },
          "mint": {
            "type": "string"
          },
          "balance": {
            "type": "number"
          },
          "minimum": {
            "type": "number"
          },
          "holder": {
            "type": "boolean"
          }
        }
      },
      "PortalHoldingError": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorMessage"
          },
          {
            "type": "object",
            "properties": {
              "wallet": {
                "type": "string"
              },
              "mint": {
                "type": "string"
              },
              "balance": {
                "type": "number"
              },
              "minimum": {
                "type": "number"
              },
              "holder": {
                "type": "boolean"
              }
            }
          }
        ]
      },
      "GatewayKeyMeta": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "prefix": {
            "type": "string"
          },
          "createdAt": {
            "type": "number"
          },
          "lastUsedAt": {
            "type": "number",
            "nullable": true
          },
          "requestCount": {
            "type": "number"
          },
          "revokedAt": {
            "type": "number",
            "nullable": true
          }
        }
      },
      "PortalMe": {
        "type": "object",
        "properties": {
          "wallet": {
            "type": "string"
          },
          "mint": {
            "type": "string"
          },
          "balance": {
            "type": "number"
          },
          "minimum": {
            "type": "number"
          },
          "holder": {
            "type": "boolean"
          },
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GatewayKeyMeta"
            }
          }
        }
      },
      "PortalKeyIssueResponse": {
        "type": "object",
        "properties": {
          "apiKey": {
            "type": "string",
            "description": "Full secret key — shown only once"
          },
          "key": {
            "$ref": "#/components/schemas/GatewayKeyMeta"
          }
        }
      },
      "TelegramStatus": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "configured": {
            "type": "boolean"
          },
          "mode": {
            "type": "string",
            "example": "webhook"
          }
        }
      },
      "TelegramUpdate": {
        "type": "object",
        "description": "Subset of Telegram Bot API Update used by the webhook handler",
        "properties": {
          "update_id": {
            "type": "integer"
          },
          "message": {
            "type": "object",
            "properties": {
              "message_id": {
                "type": "integer"
              },
              "text": {
                "type": "string"
              },
              "chat": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "integer"
                  }
                }
              },
              "from": {
                "type": "object",
                "properties": {
                  "first_name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
