{
  "version": "0.1.0",
  "name": "dox402",
  "description": "Pay-per-use AI inference gateway. Authenticate with Ethereum wallet, pay with USDC on Base Mainnet, get streamed AI responses.",
  "url": "https://inference-gate.iglesias-brandon.workers.dev",
  "openapi": "/openapi.json",
  "authentication": {
    "type": "custom",
    "description": "SIWE (EIP-4361) wallet authentication. See the 'authenticate' flow below, or use the SIGN-IN-WITH-X header for single-request auth."
  },
  "flows": [
    {
      "name": "authenticate",
      "description": "Authenticate with an Ethereum wallet using SIWE (EIP-4361) to obtain a 24-hour session token",
      "steps": [
        {
          "endpoint": "/auth/nonce",
          "method": "GET",
          "description": "Request a one-time nonce for your wallet address",
          "parameters": { "wallet": "$walletAddress" },
          "output": { "nonce": "$.nonce" }
        },
        {
          "endpoint": "/auth/login",
          "method": "POST",
          "description": "Construct an EIP-4361 message with the nonce, sign it with personal_sign, and submit both",
          "body": {
            "message": "$siweMessage",
            "signature": "$walletSignature"
          },
          "output": {
            "token": "$.token",
            "expiresAt": "$.expiresAt"
          }
        }
      ]
    },
    {
      "name": "infer",
      "description": "Run AI text generation (SSE streaming). Requires authentication and a positive token balance.",
      "requires": ["authenticate"],
      "steps": [
        {
          "endpoint": "/infer",
          "method": "POST",
          "headers": { "Authorization": "Bearer $token" },
          "body": {
            "prompt": "$prompt",
            "walletAddress": "$walletAddress",
            "model": "$model",
            "maxTokens": "$maxTokens",
            "useRag": "$useRag",
            "systemPrompt": "$systemPrompt"
          },
          "description": "Returns 200 with SSE stream if balance > 0. Returns 402 with payment instructions if balance is zero."
        }
      ]
    },
    {
      "name": "infer-json",
      "description": "Run AI text generation with synchronous JSON response (recommended for agents). Set Accept: application/json to get {response, usage, cost, model, balance} instead of SSE.",
      "requires": ["authenticate"],
      "steps": [
        {
          "endpoint": "/infer",
          "method": "POST",
          "headers": {
            "Authorization": "Bearer $token",
            "Accept": "application/json"
          },
          "body": {
            "prompt": "$prompt",
            "walletAddress": "$walletAddress",
            "model": "$model",
            "maxTokens": "$maxTokens",
            "useRag": "$useRag",
            "systemPrompt": "$systemPrompt"
          },
          "output": {
            "response": "$.response",
            "cost": "$.cost",
            "balance": "$.balance",
            "model": "$.model"
          },
          "description": "Returns 200 with JSON if balance > 0. Returns 402 with payment instructions if balance is zero."
        }
      ]
    },
    {
      "name": "check-balance",
      "description": "Query current token balance and usage statistics",
      "requires": ["authenticate"],
      "steps": [
        {
          "endpoint": "/balance",
          "method": "GET",
          "headers": { "Authorization": "Bearer $token" },
          "output": {
            "tokens": "$.tokens",
            "totalDeposited": "$.totalDeposited",
            "totalSpent": "$.totalSpent",
            "totalRequests": "$.totalRequests"
          }
        }
      ]
    },
    {
      "name": "upload-document",
      "description": "Upload a text document for RAG (retrieval-augmented generation). The document is chunked, embedded, and stored in Vectorize.",
      "requires": ["authenticate"],
      "steps": [
        {
          "endpoint": "/documents",
          "method": "POST",
          "headers": { "Authorization": "Bearer $token" },
          "body": {
            "title": "$documentTitle",
            "content": "$documentContent"
          },
          "description": "Upload plain text content (max 100KB, max 50 docs per wallet). Embedding cost deducted from balance.",
          "output": {
            "id": "$.id",
            "charCount": "$.charCount",
            "chunkCount": "$.chunkCount"
          }
        }
      ]
    },
    {
      "name": "list-documents",
      "description": "List all uploaded documents for this wallet",
      "requires": ["authenticate"],
      "steps": [
        {
          "endpoint": "/documents",
          "method": "GET",
          "headers": { "Authorization": "Bearer $token" },
          "output": {
            "documents": "$.documents"
          }
        }
      ]
    },
    {
      "name": "deposit",
      "description": "Top up token balance by submitting an on-chain USDC payment proof",
      "requires": ["authenticate"],
      "steps": [
        {
          "endpoint": "/payment-info",
          "method": "GET",
          "description": "Get the USDC payment address and network details",
          "output": {
            "paymentAddress": "$.paymentAddress",
            "usdcContract": "$.usdcContract"
          }
        },
        {
          "endpoint": "/deposit",
          "method": "POST",
          "headers": { "Authorization": "Bearer $token" },
          "body": {
            "walletAddress": "$walletAddress",
            "proof": "$base64EncodedPaymentProof"
          },
          "description": "Submit proof of on-chain USDC transfer. The proof must be signed by the wallet and the transaction must be confirmed on Base Mainnet.",
          "output": {
            "credited": "$.credited",
            "tokens": "$.tokens"
          }
        }
      ]
    }
  ]
}
