{
  "openapi": "3.1.0",
  "info": {
    "title": "refd agent-facing API",
    "version": "0.2.0",
    "summary": "Public HTTP surface an agent uses to reach refd's read-only MCP connector.",
    "description": "refd's agent interface is a remote MCP server (Streamable HTTP) behind OAuth 2.1. This catalog documents the public endpoints: OAuth discovery and flow, and the MCP endpoint itself. The nine read tools and metric-glossary resource are discovered at runtime via MCP `tools/list` and `resources/list`. Workspace data routes used by the dashboard are session-authenticated and intentionally not part of the agent surface.",
    "license": {
      "name": "MIT",
      "url": "https://github.com/emaitchess/refd/blob/main/LICENSE"
    },
    "contact": {
      "name": "refd",
      "url": "https://refd.ai/agents",
      "email": "h@emaitchess.com"
    }
  },
  "servers": [
    { "url": "https://api.refd.ai", "description": "Production API" }
  ],
  "externalDocs": {
    "description": "Agent access guide",
    "url": "https://refd.ai/agents"
  },
  "tags": [
    {
      "name": "discovery",
      "description": "OAuth 2.1 metadata (RFC 9728, RFC 8414)"
    },
    { "name": "oauth", "description": "OAuth 2.1 authorization flow" },
    { "name": "mcp", "description": "Model Context Protocol endpoint" },
    { "name": "health", "description": "Liveness" }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": ["health"],
        "summary": "Liveness probe",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "ok": { "const": true } }
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource/mcp": {
      "get": {
        "tags": ["discovery"],
        "summary": "Protected-resource metadata (RFC 9728)",
        "description": "Describes the MCP resource and the authorization servers that protect it.",
        "security": [],
        "responses": {
          "200": {
            "description": "Protected-resource metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "resource": {
                      "type": "string",
                      "format": "uri",
                      "examples": ["https://api.refd.ai/mcp"]
                    },
                    "authorization_servers": {
                      "type": "array",
                      "items": { "type": "string", "format": "uri" }
                    },
                    "scopes_supported": {
                      "type": "array",
                      "items": { "type": "string" },
                      "examples": [["data:read"]]
                    },
                    "bearer_methods_supported": {
                      "type": "array",
                      "items": { "type": "string" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "tags": ["discovery"],
        "summary": "Authorization-server metadata (RFC 8414)",
        "security": [],
        "responses": {
          "200": {
            "description": "Authorization-server metadata (issuer, endpoints, supported flows).",
            "content": {
              "application/json": { "schema": { "type": "object" } }
            }
          }
        }
      }
    },
    "/oauth/register": {
      "post": {
        "tags": ["oauth"],
        "summary": "Dynamic client registration (RFC 7591)",
        "security": [],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object" } } }
        },
        "responses": {
          "201": {
            "description": "Registered client",
            "content": {
              "application/json": { "schema": { "type": "object" } }
            }
          }
        }
      }
    },
    "/oauth/authorize": {
      "get": {
        "tags": ["oauth"],
        "summary": "Authorization endpoint",
        "description": "Starts the OAuth 2.1 authorization-code + PKCE flow. Unauthenticated users are redirected to the dashboard sign-in and then to a per-workspace consent screen.",
        "security": [],
        "parameters": [
          {
            "name": "response_type",
            "in": "query",
            "required": true,
            "schema": { "const": "code" }
          },
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "required": true,
            "schema": { "type": "string", "format": "uri" }
          },
          {
            "name": "code_challenge",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "required": true,
            "schema": { "const": "S256" }
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "examples": ["data:read"] }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": { "type": "string" }
          },
          {
            "name": "resource",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "format": "uri" }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to sign-in, consent, or back to redirect_uri with an authorization code."
          }
        }
      }
    },
    "/oauth/token": {
      "post": {
        "tags": ["oauth"],
        "summary": "Token endpoint",
        "description": "Exchanges an authorization code (or refresh token) for an access token. PKCE required.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": ["authorization_code", "refresh_token"]
                  },
                  "code": { "type": "string" },
                  "redirect_uri": { "type": "string", "format": "uri" },
                  "client_id": { "type": "string" },
                  "code_verifier": { "type": "string" },
                  "refresh_token": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Access token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "access_token": { "type": "string" },
                    "token_type": { "const": "Bearer" },
                    "expires_in": { "type": "integer" },
                    "refresh_token": { "type": "string" },
                    "scope": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "tags": ["mcp"],
        "summary": "MCP endpoint (Streamable HTTP)",
        "description": "Stateless Model Context Protocol server over JSON-RPC 2.0. Requires a Bearer access token whose grant is scoped to one workspace. Use `tools/list` to discover the nine read-only tools and `resources/list` for the metric glossary. Rate-limited per token.",
        "security": [{ "mcpOAuth": ["data:read"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "jsonrpc": { "const": "2.0" },
                  "id": { "type": ["string", "number"] },
                  "method": {
                    "type": "string",
                    "examples": ["tools/list", "tools/call", "initialize"]
                  },
                  "params": { "type": "object" }
                },
                "required": ["jsonrpc", "method"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result (or an SSE stream for streaming responses).",
            "content": {
              "application/json": { "schema": { "type": "object" } }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token. The WWW-Authenticate header points to the protected-resource metadata."
          },
          "429": { "description": "Rate limit exceeded." }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "mcpOAuth": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization-code + PKCE. Each grant is bound to a single workspace; tokens are read-only.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.refd.ai/oauth/authorize",
            "tokenUrl": "https://api.refd.ai/oauth/token",
            "scopes": {
              "data:read": "Read this workspace's AI visibility data"
            }
          }
        }
      }
    }
  }
}
