{
  "openapi": "3.1.0",
  "info": {
    "title": "AgentPay",
    "version": "1.0.0",
    "summary": "Pay-per-call gateway that lets AI agents call third-party APIs from a prepaid wallet.",
    "description": "Agents call paid APIs through AgentPay with one key. The destination API's key is added server-side. A call is charged only when the destination answers 2xx within the route's SLA; errors, timeouts and retries with the same Idempotency-Key are free. Shares API keys (fv1.*) and the prepaid wallet with Freshness Validator (https://api.myuiaf.com). Human docs: https://myuiaf.com/agentpay/docs",
    "contact": { "name": "myuiaf", "email": "hello@myuiaf.com", "url": "https://myuiaf.com/contact" },
    "termsOfService": "https://myuiaf.com/terms"
  },
  "servers": [{ "url": "https://agentpay.myuiaf.com" }],
  "externalDocs": { "url": "https://myuiaf.com/agentpay/docs" },
  "security": [{ "agentKey": [] }],
  "components": {
    "securitySchemes": {
      "agentKey": { "type": "apiKey", "in": "header", "name": "X-Agent-API-Key", "description": "fv1.<agent_id>.<key_id>.<secret>. Also accepted as X-Api-Key or Authorization: Bearer. Buy one at https://myuiaf.com/pricing#buy or POST https://api.myuiaf.com/api/v1/credits." }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error", "code"],
        "properties": {
          "error": { "type": "string" },
          "code": { "type": "string" },
          "price_usd": { "type": "number" },
          "topup": { "type": "object", "properties": { "url": { "type": "string" }, "method": { "type": "string" }, "note": { "type": "string" } } }
        }
      },
      "Route": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "example": "rt_weather" },
          "name": { "type": "string" },
          "description": { "type": "string" },
          "pricing_model": { "type": "string", "enum": ["flat_0.01", "markup_5_percent"] },
          "price_per_call_usd": { "type": "number" },
          "sla_ms": { "type": "integer" },
          "proxy_url": { "type": "string", "format": "uri" }
        }
      },
      "Call": {
        "type": "object",
        "properties": {
          "call_id": { "type": "string" },
          "idempotency_key": { "type": "string" },
          "route_id": { "type": "string" },
          "amount_usd": { "type": "number" },
          "status": { "type": "string", "enum": ["pending", "completed", "failed"] },
          "reason": { "type": ["string", "null"] },
          "destination_response_code": { "type": ["integer", "null"] },
          "ttfb_ms": { "type": ["integer", "null"] },
          "total_ms": { "type": ["integer", "null"] },
          "ledger_tx_id": { "type": ["string", "null"] },
          "created_at": { "type": "string", "format": "date-time" },
          "settled_at": { "type": ["string", "null"], "format": "date-time" }
        }
      }
    },
    "parameters": {
      "RouteId": { "name": "route_id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^rt_[a-z0-9_-]{3,40}$" } },
      "Path": { "name": "path", "in": "path", "required": true, "description": "Appended to the route's destination URL.", "schema": { "type": "string" } },
      "IdempotencyKey": { "name": "Idempotency-Key", "in": "header", "required": true, "description": "Unique per logical call, 1-255 printable characters. A completed key replays its response for 24 hours with no new charge.", "schema": { "type": "string" } }
    },
    "responses": {
      "Proxied": {
        "description": "The destination API's response, passed through. Charged only for 2xx.",
        "headers": {
          "x-agentpay-call-id": { "schema": { "type": "string" } },
          "x-agentpay-charged-usd": { "schema": { "type": "string" } },
          "x-agentpay-available-usd": { "schema": { "type": "string" } },
          "x-agentpay-ttfb-ms": { "schema": { "type": "string" } },
          "x-agentpay-total-ms": { "schema": { "type": "string" } },
          "idempotent-replayed": { "schema": { "type": "string", "enum": ["true"] } }
        }
      },
      "Error": { "description": "AgentPay error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    }
  },
  "paths": {
    "/v1/routes": {
      "get": {
        "operationId": "listRoutes",
        "summary": "List the APIs available, with price per successful call and SLA",
        "responses": {
          "200": { "description": "Routes", "content": { "application/json": { "schema": { "type": "object", "properties": { "routes": { "type": "array", "items": { "$ref": "#/components/schemas/Route" } } } } } } },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/proxy/{route_id}/{path}": {
      "parameters": [{ "$ref": "#/components/parameters/RouteId" }, { "$ref": "#/components/parameters/Path" }, { "$ref": "#/components/parameters/IdempotencyKey" }],
      "get": { "operationId": "proxyGet", "summary": "Call a paid API (GET)", "responses": { "default": { "$ref": "#/components/responses/Proxied" }, "402": { "$ref": "#/components/responses/Error" }, "504": { "$ref": "#/components/responses/Error" } } },
      "post": { "operationId": "proxyPost", "summary": "Call a paid API (POST)", "requestBody": { "required": false, "content": { "*/*": { "schema": {} } } }, "responses": { "default": { "$ref": "#/components/responses/Proxied" }, "402": { "$ref": "#/components/responses/Error" }, "504": { "$ref": "#/components/responses/Error" } } },
      "put": { "operationId": "proxyPut", "summary": "Call a paid API (PUT)", "requestBody": { "required": false, "content": { "*/*": { "schema": {} } } }, "responses": { "default": { "$ref": "#/components/responses/Proxied" } } },
      "patch": { "operationId": "proxyPatch", "summary": "Call a paid API (PATCH)", "requestBody": { "required": false, "content": { "*/*": { "schema": {} } } }, "responses": { "default": { "$ref": "#/components/responses/Proxied" } } },
      "delete": { "operationId": "proxyDelete", "summary": "Call a paid API (DELETE)", "responses": { "default": { "$ref": "#/components/responses/Proxied" } } }
    },
    "/v1/wallet/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Shared wallet balance (also used by Freshness Validator)",
        "responses": {
          "200": { "description": "Balance", "content": { "application/json": { "schema": { "type": "object", "properties": { "agent_id": { "type": "string" }, "tier": { "type": "string" }, "balance_usd": { "type": "number" }, "held_usd": { "type": "number" }, "available_usd": { "type": "number" }, "topup_url": { "type": "string" } } } } } },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/transactions": {
      "get": {
        "operationId": "listTransactions",
        "summary": "AgentPay calls, newest first",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } },
          { "name": "before", "in": "query", "description": "call_id cursor from next_before", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Calls", "content": { "application/json": { "schema": { "type": "object", "properties": { "transactions": { "type": "array", "items": { "$ref": "#/components/schemas/Call" } }, "next_before": { "type": ["string", "null"] }, "next_url": { "type": ["string", "null"] } } } } } }
        }
      }
    },
    "/v1/health": {
      "get": { "operationId": "health", "summary": "Service health", "security": [], "responses": { "200": { "description": "All dependencies reachable" }, "503": { "description": "Degraded" } } }
    }
  }
}
