{"openapi":"3.1.0","info":{"title":"RankSage API","version":"1.1.0","summary":"RankSage's agent-facing API: an MCP server plus the OAuth 2.0 flow that authorizes it.","description":"RankSage measures how AI answer engines describe a brand and joins that to search, content and behaviour data.\n\nThe primary programmatic surface is the RankSage MCP server (Model Context Protocol, Streamable HTTP transport) at https://web-production-a039f.up.railway.app/api/v1/mcp. It exposes 17 read-only tools: get_digest, get_visibility_summary, get_visibility_detail, get_ai_performance, get_search_analytics, get_traffic_summary, get_content_report, get_content_production, get_gap_counts, list_gaps, get_competitor_report, get_community_report, get_behavior_report, get_site_readiness, list_action_queue, list_conversations, get_conversation.\n\nAuthentication is OAuth 2.0 authorization-code with PKCE (S256) and RFC 7591 dynamic client registration, or a personal access token created in the RankSage app (Settings → MCP). All tools are read-only and tenant-bound server-side — no request may name another tenant.\n\nVersioning & deprecation: the API is versioned in the URL path (/api/v1). Breaking changes ship as a new path version, never in place; a scheduled retirement is announced in this document and on the developers page with at least 90 days of overlap. Additive changes (new tools, new optional fields) arrive within the current version.\n\nHuman documentation: https://www.ranksage.com/developers · Agent auth walkthrough: https://www.ranksage.com/auth.md","contact":{"name":"RankSage","url":"https://www.ranksage.com/developers","email":"hello@ranksage.com"},"termsOfService":"https://www.ranksage.com/terms"},"servers":[{"url":"https://web-production-a039f.up.railway.app","description":"RankSage API"}],"externalDocs":{"description":"RankSage developer resources","url":"https://www.ranksage.com/developers"},"security":[{"oauth2":["mcp"]},{"personalAccessToken":[]}],"tags":[{"name":"mcp","description":"Model Context Protocol server (Streamable HTTP)"},{"name":"oauth","description":"OAuth 2.0 authorization (PKCE + dynamic client registration)"},{"name":"public","description":"Public, unauthenticated endpoints"}],"paths":{"/api/v1/mcp":{"post":{"tags":["mcp"],"operationId":"mcpStreamableHttp","summary":"RankSage MCP server endpoint (Streamable HTTP, JSON-RPC 2.0)","description":"Model Context Protocol endpoint. Speaks MCP over Streamable HTTP: POST JSON-RPC 2.0 messages (initialize, tools/list, tools/call). Stateless — no SSE resume stream, no session to delete. Requires a Bearer token: an OAuth access token with the `mcp` scope, or a personal access token.","security":[{"oauth2":["mcp"]},{"personalAccessToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}},"responses":{"200":{"description":"JSON-RPC 2.0 response (application/json or text/event-stream per the MCP Streamable HTTP transport).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}},"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"Missing or invalid Bearer token, returned as a JSON-RPC error envelope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcError"}}}}}}},"/oauth/authorize":{"get":{"tags":["oauth"],"operationId":"oauthAuthorize","summary":"OAuth 2.0 authorization endpoint (browser consent, PKCE required)","description":"Standard authorization-code endpoint. PKCE with S256 is mandatory; the token endpoint uses no client secret (token_endpoint_auth_method: none).","security":[],"parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","enum":["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":{"type":"string","enum":["S256"]}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","example":"mcp"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirects to redirect_uri with `code` (and `state`) after user consent."}}}},"/api/v1/oauth/token":{"post":{"tags":["oauth"],"operationId":"oauthToken","summary":"OAuth 2.0 token endpoint (authorization_code + refresh_token)","description":"Exchanges an authorization code (with the PKCE code_verifier) for an access token, or rotates a refresh token. Refresh tokens are single-use and rotated on every exchange.","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"},"code_verifier":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"refresh_token":{"type":"string"},"client_id":{"type":"string"}},"required":["grant_type","client_id"]}}}},"responses":{"200":{"description":"Token response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Invalid grant, code, or verifier.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/oauth/register":{"post":{"tags":["oauth"],"operationId":"oauthRegisterClient","summary":"Dynamic client registration (RFC 7591)","description":"Registers an OAuth client at runtime — how MCP clients such as Claude and Cursor onboard without manual credential issuance.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"}}},"required":["redirect_uris"]}}}},"responses":{"201":{"description":"Registered client metadata including client_id."}}}},"/api/v1/oauth/revoke":{"post":{"tags":["oauth"],"operationId":"oauthRevoke","summary":"Token revocation","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"]}}}},"responses":{"200":{"description":"Token revoked (idempotent)."}}}},"/api/v1/billing/plans":{"get":{"tags":["public"],"operationId":"listPlans","summary":"Public plan catalogue (no auth)","description":"The live RankSage pricing tiers with entitlement limits. Also summarized in markdown at the marketing site's /pricing.md.","security":[],"responses":{"200":{"description":"Plan catalogue.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanCatalogueResponse"}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"tags":["oauth"],"operationId":"authorizationServerMetadata","summary":"RFC 8414 authorization server metadata","security":[],"responses":{"200":{"description":"Authorization server metadata including code_challenge_methods_supported: [S256]."}}}},"/.well-known/oauth-protected-resource":{"get":{"tags":["oauth"],"operationId":"protectedResourceMetadata","summary":"RFC 9728 protected resource metadata","security":[],"responses":{"200":{"description":"Protected resource metadata for the MCP endpoint."}}}}},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","description":"OAuth 2.0 authorization-code flow with mandatory PKCE (S256) and RFC 7591 dynamic client registration. Scopes are least-privilege: request only `mcp` unless you need conversation reads — and note that `conversations` is grantable only to in-app personal access tokens, not to OAuth clients.","flows":{"authorizationCode":{"authorizationUrl":"https://web-production-a039f.up.railway.app/oauth/authorize","tokenUrl":"https://web-production-a039f.up.railway.app/api/v1/oauth/token","refreshUrl":"https://web-production-a039f.up.railway.app/api/v1/oauth/token","scopes":{"mcp":"Read-only access to every core RankSage MCP tool: visibility, content, competitors, behaviour, traffic and the action queue. No write operations exist on this surface."}}}},"personalAccessToken":{"type":"http","scheme":"bearer","description":"Personal access token created in the RankSage app (Settings → MCP), sent as Authorization: Bearer. Tokens are scoped at creation: default scope `mcp`; `conversations` (Read stored RankSage assistant conversations. Grantable only to personal access tokens created in the RankSage app with explicit consent — OAuth grants cannot carry this scope.) is opt-in per token."}},"schemas":{"JsonRpcRequest":{"type":"object","properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"null"}]},"method":{"type":"string","examples":["initialize","tools/list","tools/call"]},"params":{"type":"object"}},"required":["jsonrpc","method"]},"JsonRpcResponse":{"type":"object","properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"null"}]},"result":{"type":"object"},"error":{"$ref":"#/components/schemas/JsonRpcErrorObject"}},"required":["jsonrpc"]},"JsonRpcError":{"type":"object","properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"null"}]},"error":{"$ref":"#/components/schemas/JsonRpcErrorObject"}},"required":["jsonrpc","error"]},"JsonRpcErrorObject":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"}},"required":["code","message"]},"TokenResponse":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","description":"Access token lifetime in seconds (1 hour)."},"refresh_token":{"type":"string","description":"Single-use; rotated on every refresh. 90-day lifetime."},"scope":{"type":"string"}},"required":["access_token","token_type"]},"ApiError":{"type":"object","description":"Standard RankSage REST error envelope.","properties":{"success":{"type":"boolean","const":false},"message":{"type":"string"}},"required":["success","message"]},"PlanCatalogueResponse":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"plans":{"type":"array","items":{"type":"object","properties":{"tier":{"type":"string","examples":["FREE","STARTER","GROWTH","PRO"]},"amountPaise":{"type":"integer"},"amountInr":{"type":"integer"},"currency":{"type":"string"},"entitlements":{"type":"object","additionalProperties":{"type":"integer"}}}}}}}}}}}}