{"openapi":"3.1.0","info":{"title":"FastDrop API","version":"1.0.1","description":"FastDrop is the liveness layer for agent-ready software: the official MCP Registry authenticates who published a server, FastDrop probes whether it still answers, and publishes the tools each endpoint actually returned.\n\nThree surfaces, one API:\n- `POST /mcp` - a Streamable HTTP MCP server (JSON-RPC 2.0). Read tools (list_launches, get_product, search_products, find_tools, list_reviews, list_comments) are unauthenticated; write tools (submit_product, update_product, toggle_vote, post_review, post_comment, recheck_mcp, check_submission_status, invite_collaborator) require a Bearer token.\n- `GET /v0.1/servers` - an MCP Registry-compatible subregistry (OpenAPI shape) with a `dev.fastdrop/verification` liveness block in `_meta`. Unauthenticated, cursor-paginated.\n- `POST /api/x402/bundles/{tier}` - x402 (USDC on Base) checkout for listing bundles, authenticated with an API key.\n\nWhen to use this API: discover agent-ready products by probed capability (not marketing tags), check whether an MCP endpoint currently answers, submit or update your own listing programmatically, and poll submission status. When NOT to use it: identity verification of server publishers (that is the official registry at registry.modelcontextprotocol.io) and human browsing (use the website).\n\nAgent resources: llms.txt at /llms.txt, developer docs at /developers, sitemap at /sitemap.xml, MCP server manifest at /.well-known/mcp.","contact":{"name":"FastDrop","url":"https://fastdrop.dev/contact","email":"privacy@fastdrop.dev"}},"servers":[{"url":"https://fastdrop.dev","description":"Production"}],"tags":[{"name":"MCP","description":"Model Context Protocol server over Streamable HTTP. JSON-RPC 2.0 bodies; see https://modelcontextprotocol.io"},{"name":"Subregistry","description":"MCP Registry OpenAPI-compatible server list with FastDrop liveness metadata added under _meta"},{"name":"Payments","description":"x402 wallet checkout for listing bundles"},{"name":"Legacy payments","description":"Payment routes for legacy unpaid listings"},{"name":"Health","description":"Liveness probes for the API itself"}],"paths":{"/mcp":{"post":{"tags":["MCP"],"operationId":"callMcp","summary":"Call an MCP method (initialize, tools/list, tools/call, ping)","description":"Single MCP Streamable HTTP endpoint. Start with `initialize`, then `tools/list`, then `tools/call`. Read tools need no auth. Write tools require `Authorization: Bearer fd_...` (API key) or an OAuth access token with the `mcp` scope - a 401 with WWW-Authenticate triggers OAuth discovery (RFC 9728). Rate limit: 60 POSTs/min per IP.","security":[{},{"ApiKeyAuth":[]},{"FastDropOAuth":["mcp"]}],"parameters":[{"name":"MCP-Protocol-Version","in":"header","required":false,"description":"Negotiated MCP protocol version. If omitted, FastDrop assumes 2025-03-26 for compatibility.","schema":{"type":"string","example":"2025-03-26"}},{"name":"Accept","in":"header","required":false,"description":"MCP clients should accept application/json and text/event-stream.","schema":{"type":"string","example":"application/json, text/event-stream"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"},"examples":{"initialize":{"summary":"Handshake","value":{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0.0"}}}},"toolsCall":{"summary":"Find products by probed capability","value":{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"find_tools","arguments":{"query":"web search"}}}}}}}},"responses":{"200":{"description":"JSON-RPC response. Tool-level failures arrive as HTTP 200 with result.isError=true; auth-gated tools arrive as HTTP 401 with a JSON-RPC body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"202":{"description":"Notification accepted; no JSON-RPC response body is returned."},"400":{"description":"Parse error, invalid request, or unsupported MCP-Protocol-Version","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"401":{"description":"Authentication required for a write tool. WWW-Authenticate points at /.well-known/oauth-protected-resource/mcp for OAuth discovery.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"403":{"description":"The request Origin is not allowed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"429":{"description":"Rate limit exceeded (60 POSTs/min per IP)","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}}}},"get":{"tags":["MCP"],"operationId":"mcpGetInfo","summary":"Method not allowed (no SSE stream on this server)","description":"This server does not offer the optional GET SSE stream. Use POST for all MCP traffic; the server manifest lives at /.well-known/mcp.","responses":{"405":{"description":"Use POST; see Allow header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v0.1/servers":{"get":{"tags":["Subregistry"],"operationId":"listServers","summary":"List MCP servers with FastDrop liveness data","description":"MCP Registry-compatible server list. Every entry carries `_meta[\"dev.fastdrop/verification\"]` with probe results: last_probed, answered, keyed, tools_count, consecutive_failures, package_only, and the FastDrop listing URLs. Healthy endpoints are re-probed every 30 days; after 15 consecutive failures an endpoint drops out of rotation. Unauthenticated.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":30},"description":"Page size"},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Pagination cursor from metadata.nextCursor (format name:version)"},{"name":"updated_since","in":"query","schema":{"type":"string","format":"date-time"},"description":"RFC3339 filter on registry updates; implies include_deleted"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring match on the reverse-DNS server name"},{"name":"version","in":"query","schema":{"type":"string"},"description":"Pass \"latest\" (default behavior) or an exact version string"},{"name":"include_deleted","in":"query","schema":{"type":"boolean","default":false},"description":"Include servers the official registry marked deleted"}],"responses":{"200":{"description":"Server list with verification metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerList"}}}},"400":{"description":"Invalid updated_since (must be RFC3339)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}}},"/v0.1/servers/{serverName}/versions":{"get":{"tags":["Subregistry"],"operationId":"listServerVersions","summary":"List all versions of one MCP server","description":"All published versions for a reverse-DNS server name, each with the FastDrop verification block. 404 when the name is unknown.","parameters":[{"name":"serverName","in":"path","required":true,"schema":{"type":"string"},"description":"Reverse-DNS server name, e.g. io.github.example/weather","example":"io.github.example/weather"},{"name":"include_deleted","in":"query","schema":{"type":"boolean","default":false},"description":"Include deleted versions"}],"responses":{"200":{"description":"Version list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerList"}}}},"404":{"description":"Server not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}}},"/v0.1/servers/{serverName}/versions/{version}":{"get":{"tags":["Subregistry"],"operationId":"getServerVersion","summary":"Get one version of an MCP server","description":"A single server version record with the FastDrop verification block.","parameters":[{"name":"serverName","in":"path","required":true,"schema":{"type":"string"},"description":"Reverse-DNS server name, including its slash separator","example":"io.github.example/weather"},{"name":"version","in":"path","required":true,"schema":{"type":"string"},"description":"Exact semantic version or `latest`","example":"1.2.0"},{"name":"include_deleted","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include a soft-deleted version when true"}],"responses":{"200":{"description":"The server version record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerEntry"}}}},"404":{"description":"Server or version not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}}},"/v0.1/health":{"get":{"tags":["Health"],"operationId":"getSubregistryHealth","summary":"Subregistry liveness probe","description":"Static ok/no-store probe in the official registry shape. Unauthenticated.","responses":{"200":{"description":"Subregistry is up","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]}},"required":["status"]}}}}}}},"/health":{"get":{"tags":["Health"],"operationId":"getHealth","summary":"Service health including database reachability","description":"Reports ok only when the process answers and PostgreSQL responds to SELECT 1. 503 when degraded.","responses":{"200":{"description":"Healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"db":{"type":"string","enum":["ok"]},"timestamp":{"type":"string","format":"date-time"}},"required":["status","db","timestamp"]}}}},"503":{"description":"Degraded (database unreachable)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["degraded"]},"db":{"type":"string","enum":["error"]},"timestamp":{"type":"string","format":"date-time"}},"required":["status","db","timestamp"]}}}}}}},"/api/x402/bundles/{tier}":{"post":{"tags":["Payments"],"operationId":"payForBundle","summary":"Buy a listing bundle over x402 (USDC on Base)","description":"Requires an API key. Without an X-PAYMENT header, returns HTTP 402 with an x402 payment challenge in `accepts`. Replay the same request with the signed payment header to settle; the endpoint is idempotent per purchase. Tiers: starter (3 listing credits, $5), unlimited (12 months of unlimited listings, $9), or an $8 upgrade when an active Starter bundle already exists.","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tier","in":"path","required":true,"schema":{"type":"string","enum":["starter","unlimited"]},"description":"Bundle tier to purchase"},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"type":"string"},"description":"Signed x402 payment payload. Omit on the first request to receive a 402 challenge."}],"requestBody":{"required":false,"description":"Optional payer-country evidence used for tax compliance.","content":{"application/json":{"schema":{"type":"object","properties":{"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2 country code"}}}}}},"responses":{"200":{"description":"Bundle paid and activated","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","refund_due"]},"tier":{"type":"string","enum":["starter","unlimited"]},"purchaseId":{"type":"string"},"amountCents":{"type":"integer"}},"required":["status","tier","purchaseId"]}}}},"202":{"description":"Settlement pending reconciliation - poll the same purchase before retrying","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["settled","settling"]},"purchaseId":{"type":"string"},"note":{"type":"string"}},"required":["status","purchaseId","note"]}}}},"400":{"description":"Invalid bundle tier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"402":{"description":"x402 payment challenge (no X-PAYMENT header on first call)","content":{"application/json":{"schema":{"type":"object","properties":{"x402Version":{"type":"integer","enum":[1]},"error":{"type":"string"},"purchaseId":{"type":"string"},"accepts":{"type":"array","items":{"type":"object"},"description":"x402 payment requirements"}},"required":["error","accepts"]}}}},"403":{"description":"Account unavailable or listing entitlement suspended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Another settlement attempt already holds the purchase claim","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"x402 payments are temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/x402/pay/{slug}":{"post":{"tags":["Legacy payments"],"operationId":"payLegacyListing","summary":"Pay for a legacy unpaid listing over x402","description":"Legacy route for listings submitted before account bundles. Omit X-PAYMENT to receive a payment challenge, then retry with the signed payment. New submissions should use an account bundle and MCP submit_product.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]+$","maxLength":80},"description":"Product slug"},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"type":"string"},"description":"Signed x402 payment payload. Omit on the first request to receive a 402 challenge."}],"requestBody":{"required":false,"description":"Optional payer-country evidence used for tax compliance.","content":{"application/json":{"schema":{"type":"object","properties":{"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2 country code"}}}}}},"responses":{"200":{"description":"Listing is paid and pending review, live, or already paid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegacyPaymentResult"}}}},"202":{"description":"Settlement outcome is unconfirmed. Do not retry; poll /api/x402/status/{slug}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegacySettlementPending"}}}},"400":{"description":"Invalid slug","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"402":{"description":"x402 payment challenge or payment verification failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Maker account is banned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Listing state no longer accepts payment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"x402 payments are temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/x402/submit":{"post":{"tags":["Legacy payments"],"operationId":"retiredX402Submit","summary":"Retired anonymous x402 submission route","description":"Always returns HTTP 410. Create an API key, buy an account bundle, then call the MCP submit_product tool.","responses":{"410":{"description":"Route retired with migration links","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetiredRoute"}}}}}}},"/api/x402/status/{slug}":{"get":{"tags":["Payments"],"operationId":"getSubmissionStatus","summary":"Poll the public status of a submission","description":"Keyless status poll for wallet-agent submissions and live public listings. Non-live human-owned submissions are hidden and return 404. Status values: unpaid, pending, live, rejected. Rate limit: 30 req/min per IP.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]+$"},"description":"Product slug","example":"weather"}],"responses":{"200":{"description":"Submission status","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["unpaid","pending","live","rejected"]},"paid":{"type":"boolean"},"hasPaymentRecord":{"type":"boolean"},"promo":{"type":["string","null"]},"agentSubmitted":{"type":"boolean"},"rejectionPreset":{"type":["string","null"]},"reviewNote":{"type":["string","null"]},"launchedAt":{"type":["string","null"],"format":"date-time"},"page":{"type":"string","format":"uri"},"claim":{"type":["string","null"],"format":"uri"}},"required":["slug","name","status","paid","hasPaymentRecord","promo","agentSubmitted","rejectionPreset","reviewNote","launchedAt","page","claim"]}}}},"400":{"description":"Invalid slug","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Product not found (or hidden from anonymous probes)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit exceeded (30 req/min per IP)","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"fd_","description":"FastDrop API key (starts with fd_). Create one in the dashboard at /app/developer (Developer tab). Grants read access plus write access to your own submissions, votes, reviews, and comments over /mcp and the x402 bundle endpoints. Revoke any time; no scope narrowing on keys - prefer OAuth when a client only needs MCP access."},"FastDropOAuth":{"type":"oauth2","description":"OAuth 2 for MCP clients (RFC 8414 metadata at /.well-known/oauth-authorization-server, protected-resource metadata at /.well-known/oauth-protected-resource/mcp). Public clients supported (empty client secret on the token endpoint).","flows":{"authorizationCode":{"authorizationUrl":"https://fastdrop.dev/api/auth/oauth2/authorize","tokenUrl":"https://fastdrop.dev/api/auth/oauth2/token","refreshUrl":"https://fastdrop.dev/api/auth/oauth2/token","scopes":{"mcp":"Call the FastDrop MCP server (/mcp) on behalf of the signed-in user. Read tools plus their own submissions, votes, reviews, and comments - nothing else.","offline_access":"Receive refresh tokens so a long-lived agent session can renew access without re-consent."}}}}},"schemas":{"Error":{"type":"object","description":"Structured error returned by REST endpoints (MCP uses JSON-RPC errors)","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Stable machine-readable error code","example":"NOT_FOUND"},"message":{"type":"string","description":"Human-readable message"},"hint":{"type":"string","description":"Resolution hint for agents","example":"See /openapi.json for the API surface."},"docs":{"type":"string","format":"uri","description":"Documentation URL"}},"required":["code","message"]}},"required":["error"]},"ApiError":{"type":"object","description":"Existing public endpoint error shape. The error string is stable for compatibility; optional fields carry payment or retry context.","properties":{"error":{"type":"string"},"x402Version":{"type":"integer","enum":[1]},"next":{"type":"string"},"retryAfter":{"type":"integer"},"purchaseId":{"type":"string"},"accepts":{"type":"array","items":{"type":"object"}}},"required":["error"]},"LegacyPaymentResult":{"type":"object","description":"Result for a legacy listing that is paid, live, or awaiting review.","properties":{"status":{"type":"string","enum":["pending","live"]},"slug":{"type":"string"},"page":{"type":"string"},"amount":{"type":"string","description":"Atomic USDC amount when newly paid"},"cents":{"type":"integer","description":"USD cents when newly paid"},"refundDue":{"type":"boolean"},"note":{"type":"string"}},"required":["status","slug","page"]},"LegacySettlementPending":{"type":"object","properties":{"x402Version":{"type":"integer","enum":[1]},"status":{"type":"string","enum":["settling"]},"slug":{"type":"string"},"note":{"type":"string"}},"required":["x402Version","status","slug","note"]},"RetiredRoute":{"type":"object","properties":{"error":{"type":"string"},"next":{"type":"string"},"mcp":{"type":"string","format":"uri"},"bundles":{"type":"object","properties":{"starter":{"type":"string","format":"uri"},"unlimited":{"type":"string","format":"uri"}},"required":["starter","unlimited"]},"auth":{"type":"string"}},"required":["error","next","mcp","bundles","auth"]},"ProblemDetails":{"type":"object","description":"MCP Registry-compatible problem details.","properties":{"title":{"type":"string"},"detail":{"type":"string"},"status":{"type":"integer"}},"required":["title","detail","status"]},"JsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"description":"Request id (omit for notifications)","type":["string","number"]},"method":{"type":"string","enum":["initialize","tools/list","tools/call","ping","resources/list","prompts/list"]},"params":{"type":"object"}}},"JsonRpcResponse":{"type":"object","required":["jsonrpc","id"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"type":["string","number","null"]},"result":{"type":"object","description":"Method-specific result. tools/call results carry content[], structuredContent, and optional isError=true for tool-level failures."},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"}}}}},"VerificationMeta":{"type":"object","description":"FastDrop probe results for one MCP endpoint","properties":{"last_probed":{"type":["string","null"],"format":"date-time"},"answered":{"type":"boolean","description":"True when the endpoint completed initialize + tools/list"},"keyed":{"type":"boolean","description":"True when the probe used a maker-supplied read-only credential"},"tools_count":{"type":"integer"},"consecutive_failures":{"type":"integer"},"package_only":{"type":"boolean","description":"stdio package server - no URL to probe"},"product_slug":{"type":["string","null"]},"product_url":{"type":["string","null"],"format":"uri"}}},"ServerEntry":{"type":"object","required":["server","_meta"],"properties":{"server":{"type":"object","description":"MCP Registry server record (name, version, remotes, packages, description)","properties":{"name":{"type":"string"},"version":{"type":"string"},"description":{"type":"string"},"remotes":{"type":"array","items":{"type":"object"}}},"required":["name","version","description"]},"_meta":{"type":"object","properties":{"io.modelcontextprotocol.registry/official":{"type":"object","properties":{"status":{"type":"string"},"publishedAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"isLatest":{"type":"boolean"}}},"dev.fastdrop/verification":{"$ref":"#/components/schemas/VerificationMeta"}}}}},"ServerList":{"type":"object","required":["servers","metadata"],"properties":{"servers":{"type":"array","items":{"$ref":"#/components/schemas/ServerEntry"}},"metadata":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","minimum":0},"nextCursor":{"type":"string","description":"Cursor for the next page; omitted when exhausted"}}}}}}},"externalDocs":{"description":"FastDrop developer documentation","url":"https://fastdrop.dev/developers"}}