{
  "openapi": "3.1.0",
  "info": {
    "title": "SOLGPT Open API",
    "version": "1.3.0",
    "summary": "Non-custodial Solana desk data API plus inference catalog",
    "description": "Read-only market, wallet, chain, quote, perps, and inference-catalog data served by the SOLGPT desk.\n\nEvery `/api/v1/*` request except `GET /api/v1/health` requires an API key. Unauthenticated callers receive `401 api_key_required`. There is no public anonymous data surface on this contract. The human catalog at `/inference` and public `GET /api/inference` share the same secret-free builder as `GET /api/v1/inference`.\n\n1. Connect a wallet holding $CLAWD at [solgpt.us/keys](https://solgpt.us/keys)\n2. Mint a personal key (`solgpt_sk_…`) — shown exactly once\n3. Send it as `Authorization: Bearer solgpt_sk_…` or `X-API-Key`\n\nThe same keys also authenticate the official MCP server at `/api/mcp`. Keys are read-only by design — no spend scope exists. The desk never holds your private keys; these APIs never move funds. POST `/api/v1/*` is `405 method_not_allowed`.",
    "contact": { "name": "SOLGPT", "url": "https://solgpt.us" }
  },
  "servers": [
    { "url": "/", "description": "This desk" },
    { "url": "https://solgpt.us", "description": "Production desk" },
    { "url": "https://solgpt.trade", "description": "Production alias" },
    { "url": "https://x402.life", "description": "Production alias" }
  ],
  "security": [{ "bearerAuth": [] }, { "apiKeyHeader": [] }],
  "tags": [
    { "name": "market", "description": "Prices, search, tape, charts, holders" },
    { "name": "quote", "description": "Unsigned Jupiter swap quotes" },
    { "name": "chain", "description": "Addresses and transactions via Helius" },
    { "name": "wallet", "description": "Balances, assets, and net worth" },
    { "name": "perps", "description": "Phoenix perpetual markets" },
    { "name": "inference", "description": "Providers, chat/media models, studio actions, and tools" },
    { "name": "keys", "description": "Self-serve API key management (session-gated)" },
    { "name": "mcp", "description": "Official Streamable HTTP MCP server" },
    { "name": "sponge", "description": "SOLGPT Solana API (merchant SOLgpt) plus monthly SPONGE_API_KEY mint" }
  ],
  "paths": {
    "/sponge": {
      "get": {
        "operationId": "spongeManifest",
        "tags": ["sponge"],
        "summary": "SOLGPT Solana API manifest",
        "description": "Free catalog for merchant SOLgpt. Lists 20 charge endpoints ($0.00–$0.05), x402 https://api.paysponge.com/x402/purchase/svc_da69sc0pd1tk0ytjg, MPP twin, and SPONGE_API_KEY tiers ($4.20 base / $20 premium).",
        "security": [],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" }
        }
      }
    },
    "/sponge/health": {
      "get": {
        "operationId": "spongeHealth",
        "tags": ["sponge"],
        "summary": "Sponge upstream liveness",
        "security": [],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" }
        }
      }
    },
    "/sponge/price": {
      "get": {
        "operationId": "spongePrice",
        "tags": ["sponge"],
        "summary": "Spot USD price ($0.01)",
        "description": "Paid. Call via the Sponge x402/MPP purchase URL or a monthly sgk_ key. Direct unpaid GET returns 401.",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/sponge/keys": {
      "get": {
        "operationId": "spongeKeyCatalog",
        "tags": ["sponge"],
        "summary": "SPONGE_API_KEY tiers",
        "description": "Free. Base $4.20 / 30d and premium $20 / 30d. USDC or $CLAWD burn. payTo is SPONGE_PAYMENT_WALLET. Merchant SOLgpt.",
        "security": [],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" }
        }
      },
      "post": {
        "operationId": "mintSpongeApiKey",
        "tags": ["sponge"],
        "summary": "Mint a monthly SPONGE_API_KEY",
        "description": "Unpaid requests return HTTP 402 with Solana USDC and $CLAWD-burn accepts. After payment returns sgk_… once. Not LIVE_MODE_API_KEY.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tier": { "type": "string", "enum": ["base", "premium"] }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "$ref": "#/components/responses/JsonResult" },
          "402": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "operationId": "health",
        "tags": ["market"],
        "summary": "Liveness probe",
        "security": [],
        "responses": {
          "200": {
            "description": "API is up",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "const": true },
                    "api": { "type": "string", "const": "solgpt-v1" }
                  },
                  "required": ["ok", "api"]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/price": {
      "get": {
        "operationId": "getPrice",
        "tags": ["market"],
        "summary": "Spot USD price for a mint",
        "description": "Prefers Birdeye `/defi/price`; falls back to Jupiter Price V3 when Birdeye is rate-limited.",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": { "type": "string" },
            "description": "Solana mint address",
            "example": "So11111111111111111111111111111111111111112"
          }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "502": { "$ref": "#/components/responses/UpstreamFailed" }
        }
      }
    },
    "/api/v1/search": {
      "get": {
        "operationId": "searchTokens",
        "tags": ["market"],
        "summary": "Search tokens by name, symbol, or address",
        "parameters": [
          { "name": "q", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BONK" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 20, "default": 10 } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/resolve": {
      "get": {
        "operationId": "resolveToken",
        "tags": ["market"],
        "summary": "Resolve a ticker or mint to token metadata",
        "description": "Same executor as desk `resolve_token`. Pass a ticker like SOL or a mint address.",
        "parameters": [
          { "name": "q", "in": "query", "required": true, "schema": { "type": "string" }, "example": "CLAWD", "description": "Ticker or mint" }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/tape": {
      "get": {
        "operationId": "getTape",
        "tags": ["market"],
        "summary": "Market board sorted by 24h volume",
        "description": "Birdeye Token List V3 → Jupiter trending → Solana Tracker fallback chain.",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 40 } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/trending": {
      "get": {
        "operationId": "getTrending",
        "tags": ["market"],
        "summary": "Trending Solana tokens (Jupiter)",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 20, "default": 10 } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/chart": {
      "get": {
        "operationId": "getChart",
        "tags": ["market"],
        "summary": "OHLCV candles for a mint",
        "parameters": [
          { "name": "token", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Solana mint address" },
          { "name": "type", "in": "query", "schema": { "type": "string", "default": "15m", "examples": ["1s", "15s", "1m", "15m", "1H", "1D"] }, "description": "Candle interval" }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/quote": {
      "get": {
        "operationId": "getQuote",
        "tags": ["quote"],
        "summary": "Unsigned Jupiter swap quote",
        "description": "Returns a quote only. Never builds or signs a transaction. Amount is raw smallest units (lamports for SOL).",
        "parameters": [
          { "name": "inputMint", "in": "query", "required": true, "schema": { "type": "string" }, "example": "So11111111111111111111111111111111111111112" },
          { "name": "outputMint", "in": "query", "required": true, "schema": { "type": "string" } },
          { "name": "amount", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Raw amount in smallest units" },
          { "name": "slippageBps", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 5000 } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "502": { "$ref": "#/components/responses/UpstreamFailed" }
        }
      }
    },
    "/api/v1/token/{mint}": {
      "get": {
        "operationId": "getTokenOverview",
        "tags": ["market"],
        "summary": "Token overview — price, mcap, volume, holders",
        "parameters": [
          { "name": "mint", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/holders": {
      "get": {
        "operationId": "getTokenHolders",
        "tags": ["market"],
        "summary": "Token holder list",
        "parameters": [
          { "name": "token", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Mint address" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/address/{address}": {
      "get": {
        "operationId": "getAddressOverview",
        "tags": ["chain"],
        "summary": "Address overview — SOL balance, tokens, recent activity",
        "parameters": [
          { "name": "address", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/tx/{signature}": {
      "get": {
        "operationId": "getTransactionOverview",
        "tags": ["chain"],
        "summary": "Parsed transaction overview for a signature",
        "parameters": [
          { "name": "signature", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/wallet/{owner}": {
      "get": {
        "operationId": "getNetWorth",
        "tags": ["wallet"],
        "summary": "Wallet net worth + top holdings",
        "parameters": [
          { "name": "owner", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/balance/{owner}": {
      "get": {
        "operationId": "getSolBalance",
        "tags": ["wallet"],
        "summary": "SOL balance for a wallet",
        "parameters": [
          { "name": "owner", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/assets/{owner}": {
      "get": {
        "operationId": "getWalletAssets",
        "tags": ["wallet"],
        "summary": "Wallet SOL + SPL holdings snapshot",
        "parameters": [
          { "name": "owner", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 20 } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/priority-fee": {
      "get": {
        "operationId": "getPriorityFee",
        "tags": ["chain"],
        "summary": "Helius priority fee estimate",
        "parameters": [
          { "name": "account", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Account key to estimate for. Repeat the query param for multiple keys (max 20)." }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "502": { "$ref": "#/components/responses/UpstreamFailed" }
        }
      }
    },
    "/api/v1/inference": {
      "get": {
        "operationId": "listInference",
        "tags": ["inference"],
        "summary": "List providers, models, studio media, and tools",
        "description": "Catalog of every inference provider and model the desk offers: Venice chat/image/video/TTS/ASR/music, xAI Grok, OpenRouter, Moonshot, Poolside, DeepSeek, Z.AI, Hauhau, RedPill TEE, Messari, plus Composio SaaS tools and the studio action set. Same ids as the desk picker and `/inference`. No API-key secrets — env names only. Requires a `solgpt_sk_…` key; the public twin is `GET /api/inference`.",
        "responses": {
          "200": {
            "description": "Secret-free inference catalog",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceCatalog" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/phoenix/markets": {
      "get": {
        "operationId": "listPhoenixMarkets",
        "tags": ["perps"],
        "summary": "List Phoenix perpetual markets",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/JsonResult" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/keys": {
      "post": {
        "operationId": "createApiKey",
        "tags": ["keys"],
        "summary": "Mint a new API key",
        "description": "**Session-gated** (Privy cookie or Phantom SIWS JWT + $CLAWD holder proof), not key-gated. The raw secret is returned exactly once and stored only as a SHA-256 hash.",
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string", "maxLength": 80, "description": "Optional label" },
                  "scopes": { "type": "array", "items": { "type": "string", "enum": ["read", "mcp"] }, "default": ["read", "mcp"] }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key created — save `key` now; it cannot be recovered",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MintedApiKey" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "description": "$CLAWD holder gate denied" },
          "503": { "description": "Database unavailable (DATABASE_URL unset)" }
        }
      },
      "get": {
        "operationId": "listApiKeys",
        "tags": ["keys"],
        "summary": "List your API keys (masked)",
        "security": [],
        "responses": {
          "200": {
            "description": "Masked keys owned by the session wallet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": { "type": "array", "items": { "$ref": "#/components/schemas/MaskedApiKey" } }
                  },
                  "required": ["keys"]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/keys/{id}": {
      "delete": {
        "operationId": "revokeApiKey",
        "tags": ["keys"],
        "summary": "Revoke one of your API keys",
        "security": [],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Revoked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string" },
                    "revoked": { "type": "boolean", "const": true }
                  },
                  "required": ["id", "revoked"]
                }
              }
            }
          },
          "404": { "description": "Already revoked or not owned by you" }
        }
      }
    },
    "/api/gateway/keys": {
      "post": {
        "operationId": "createGatewayKey",
        "tags": ["keys"],
        "summary": "Mint an LLM gateway key",
        "description": "**Session-gated** (Privy cookie or Phantom SIWS JWT + $CLAWD holder proof). Returns a raw `llmg_…` secret exactly once. The hash is stored in `llm_gateway_api_keys` and authenticates `https://solgpt.us/gateway/v1` (OpenAI-compatible chat and Venice media). Upstream provider keys never leave the gateway.",
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string", "maxLength": 80, "description": "Optional label" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key created — save `key` now; it cannot be recovered",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string", "format": "uuid" },
                    "name": { "type": "string" },
                    "key": { "type": "string", "description": "Raw `llmg_…` secret, shown once" },
                    "prefix": { "type": "string", "minLength": 12, "maxLength": 12 },
                    "base_url": { "type": "string", "example": "https://solgpt.us/gateway/v1" },
                    "created_at": { "type": "string", "format": "date-time" }
                  },
                  "required": ["id", "key", "prefix", "base_url"]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "description": "$CLAWD holder gate denied" },
          "409": { "description": "Active key limit (5 per wallet)" },
          "503": { "description": "Database unavailable (DATABASE_URL unset)" }
        }
      },
      "get": {
        "operationId": "listGatewayKeys",
        "tags": ["keys"],
        "summary": "List your LLM gateway keys (masked)",
        "security": [],
        "responses": {
          "200": {
            "description": "Masked keys owned by the session wallet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "base_url": { "type": "string" },
                    "keys": { "type": "array", "items": { "type": "object" } }
                  },
                  "required": ["keys"]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/gateway/keys/{id}": {
      "delete": {
        "operationId": "revokeGatewayKey",
        "tags": ["keys"],
        "summary": "Revoke one of your LLM gateway keys",
        "security": [],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Revoked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string" },
                    "revoked": { "type": "boolean", "const": true }
                  },
                  "required": ["id", "revoked"]
                }
              }
            }
          },
          "404": { "description": "Already revoked or not owned by you" }
        }
      }
    },
    "/api/mcp": {
      "get": {
        "operationId": "mcpStreamableHttpGet",
        "tags": ["mcp"],
        "summary": "Official SOLGPT MCP server (Streamable HTTP GET)",
        "description": "Same auth as POST. Requires a `solgpt_sk_…` key with the `mcp` scope or `SOLGPT_MCP_TOKEN`.",
        "responses": {
          "200": { "description": "JSON-RPC response or SSE stream" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "operationId": "mcpStreamableHttp",
        "tags": ["mcp"],
        "summary": "Official SOLGPT MCP server (Streamable HTTP)",
        "description": "Same safe remote tool surface the desk chat uses (`resolve_token`, `get_price`, `search_birdeye`, …). Auth accepts either a `solgpt_sk_…` API key with the `mcp` scope or the operator `SOLGPT_MCP_TOKEN`. Unauthenticated callers receive 401.",
        "responses": {
          "200": { "description": "JSON-RPC response or SSE stream" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    }
  },
  "webhooks": {},
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "`Authorization: Bearer solgpt_sk_…` — mint at POST /api/keys"
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Alternative to the Bearer header"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "description": "Machine-readable error code" },
          "reason": { "type": "string" },
          "parameter": { "type": "string", "description": "Missing/invalid parameter name, when applicable" },
          "docs": { "type": "string", "description": "Path to the API reference" },
          "keys": { "type": "string", "description": "Path to key management" }
        },
        "required": ["error"]
      },
      "MintedApiKey": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": ["string", "null"] },
          "key": { "type": "string", "pattern": "^solgpt_sk_[A-Za-z0-9]{40}$", "description": "Full secret — shown exactly once" },
          "prefix": { "type": "string", "description": "Display-safe prefix" },
          "scopes": { "type": "array", "items": { "type": "string" } },
          "created_at": { "type": "string", "format": "date-time" },
          "note": { "type": "string" }
        },
        "required": ["id", "key", "prefix", "scopes"]
      },
      "MaskedApiKey": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": ["string", "null"] },
          "prefix": { "type": "string" },
          "scopes": { "type": "array", "items": { "type": "string" } },
          "created_at": { "type": ["string", "null"], "format": "date-time" },
          "last_used_at": { "type": ["string", "null"], "format": "date-time" },
          "request_count": { "type": "integer" },
          "revoked_at": { "type": ["string", "null"], "format": "date-time" }
        },
        "required": ["id", "prefix", "scopes", "request_count"]
      },
      "InferenceCatalog": {
        "type": "object",
        "description": "Secret-free catalog shared by /inference, GET /api/inference, and GET /api/v1/inference",
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "api": { "type": "string", "const": "solgpt-v1" },
          "version": { "type": "string" },
          "providers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "string" },
                "label": { "type": "string" },
                "blurb": { "type": "string" },
                "env": { "type": "string", "description": "Env var name only — never a secret value" },
                "kinds": { "type": "array", "items": { "type": "string" } }
              },
              "required": ["id", "label"]
            }
          },
          "models": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "string" },
                "label": { "type": "string" },
                "provider": { "type": "string" },
                "kind": { "type": "string" },
                "blurb": { "type": "string" }
              },
              "required": ["id", "kind"]
            }
          },
          "tools": { "type": "array", "items": { "type": "object" } },
          "studio": {
            "type": "object",
            "properties": {
              "route": { "type": "string" },
              "actions": { "type": "array", "items": { "type": "string" } },
              "imageModels": { "type": "array", "items": { "type": "string" } },
              "videoModels": { "type": "array", "items": { "type": "string" } },
              "ttsModels": { "type": "array", "items": { "type": "string" } },
              "asrModels": { "type": "array", "items": { "type": "string" } },
              "musicModels": { "type": "array", "items": { "type": "string" } }
            }
          }
        },
        "required": ["providers", "models", "studio"]
      }
    },
    "responses": {
      "JsonResult": {
        "description": "Executor result (shape varies per endpoint)",
        "content": { "application/json": { "schema": {} } }
      },
      "BadRequest": {
        "description": "Missing or invalid parameter",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Unauthorized": {
        "description": "API key missing, malformed, unknown, or revoked",
        "headers": {
          "WWW-Authenticate": { "schema": { "type": "string" } }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "RateLimited": {
        "description": "Per-key rate limit exceeded (default 120 req/min)",
        "headers": {
          "Retry-After": { "schema": { "type": "integer" } }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "UpstreamFailed": {
        "description": "Upstream provider failed",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    },
    "examples": {}
  },
  "x-solgpt": {
    "keyFormat": "solgpt_sk_ + 40 base62 characters",
    "rateLimit": "120 requests/minute per key (SOLGPT_API_KEY_RPM)",
    "storage": "SHA-256 hash only — plaintext never persisted",
    "spendScope": "none — v1 is read-only by design",
    "unauthenticated": "GET /api/v1/health only",
    "scalarDocs": "/docs",
    "merchant": "SOLgpt",
    "sponge": {
      "upstream": "https://solgpt.us/sponge",
      "x402": "https://api.paysponge.com/x402/purchase/svc_da69sc0pd1tk0ytjg",
      "mpp": "https://api.paysponge.com/mpp/purchase/svc_da69sc0pd1tk0ytjg",
      "keyMint": "/api/sponge/keys",
      "keyTiersUsd": { "base": 4.2, "premium": 20 }
    }
  }
}
