{"openapi":"3.0.3","info":{"title":"Sandwich Public API","version":"1.0.0","summary":"Public care-directory MCP, markdown negotiation, and discovery for joinsandwich.com.","description":"Machine-readable API for the Sandwich marketing and directory site (www.joinsandwich.com). The public MCP is read-only and requires no auth. Private Care Circle tools and OAuth 2.0 live on inbox.lovedone.app (see /.well-known/oauth-authorization-server).","contact":{"name":"Sandwich","email":"hello@joinsandwich.com","url":"https://www.joinsandwich.com/agents"},"license":{"name":"Proprietary","url":"https://www.joinsandwich.com/terms"}},"servers":[{"url":"https://www.joinsandwich.com","description":"Production (canonical www host)"},{"url":"https://joinsandwich.com","description":"Apex host (redirects to www)"}],"tags":[{"name":"Discovery","description":"Machine-readable indexes and catalogs."},{"name":"MCP","description":"Public Model Context Protocol endpoint."},{"name":"Content","description":"Markdown representations of directory pages."},{"name":"Newsletter","description":"Public newsletter signup."},{"name":"Auth","description":"Firebase session helpers used by the website."},{"name":"Community","description":"Channel community threads (authenticated writes)."}],"paths":{"/openapi.json":{"get":{"tags":["Discovery"],"operationId":"getOpenApi","summary":"OpenAPI 3 specification","responses":{"200":{"description":"OpenAPI 3.0 document","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agents.json":{"get":{"tags":["Discovery"],"operationId":"getAgentsManifest","summary":"Agent and MCP discovery manifest","responses":{"200":{"description":"Agent discovery document","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/llms.txt":{"get":{"tags":["Discovery"],"operationId":"getLlmsTxt","summary":"llms.txt index of canonical pages","responses":{"200":{"description":"Markdown index","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/llms-full.txt":{"get":{"tags":["Discovery"],"operationId":"getLlmsFullTxt","summary":"Expanded llms.txt index","responses":{"200":{"description":"Markdown index","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/.well-known/api-catalog":{"get":{"tags":["Discovery"],"operationId":"getApiCatalog","summary":"RFC 9727 API catalog linkset","responses":{"200":{"description":"Linkset","content":{"application/linkset+json":{"schema":{"type":"object"}}}}}}},"/.well-known/mcp/server.json":{"get":{"tags":["Discovery"],"operationId":"getMcpServerJson","summary":"MCP registry server.json","responses":{"200":{"description":"MCP server metadata","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/.well-known/mcp.json":{"get":{"tags":["Discovery"],"operationId":"getMcpJson","summary":"Root-path mirror of MCP server.json","responses":{"200":{"description":"MCP server metadata","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"tags":["Discovery"],"operationId":"getOauthAuthorizationServer","summary":"RFC 8414 authorization server metadata","description":"Advertises the existing LovedOne / Sandwich authorization server (issuer https://inbox.lovedone.app). This host does not issue tokens.","responses":{"200":{"description":"Authorization server metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthAuthorizationServer"}}}}}}},"/api/mcp":{"get":{"tags":["MCP"],"operationId":"getPublicMcpMetadata","summary":"Public MCP server metadata and tool list","responses":{"200":{"description":"MCP endpoint description","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"tags":["MCP"],"operationId":"postPublicMcp","summary":"JSON-RPC 2.0 MCP call (streamable HTTP)","description":"Public read-only MCP. No authentication. Methods: initialize, ping, tools/list, tools/call, notifications/initialized. Tools: search_care_resources, get_channel, calculate_long_term_care_cost.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"},"examples":{"toolsList":{"value":{"jsonrpc":"2.0","id":1,"method":"tools/list"}},"search":{"value":{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_care_resources","arguments":{"query":"medicaid look-back","limit":5}}}}}}}},"responses":{"200":{"description":"JSON-RPC success or protocol-level error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"204":{"description":"notifications/initialized acknowledged"},"400":{"description":"Invalid JSON-RPC envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}}}}},"/api/md":{"get":{"tags":["Content"],"operationId":"getMarkdownByAccept","summary":"Markdown representation of a content page","description":"Used when a page is requested with Accept: text/markdown. The original path is supplied via the x-md-original-path header (set by the site proxy) or a path query parameter.","parameters":[{"name":"path","in":"query","required":false,"schema":{"type":"string"},"description":"Site path to render, e.g. /nb/medicaid"},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","example":"text/markdown"}}],"responses":{"200":{"description":"Markdown document","headers":{"Vary":{"schema":{"type":"string","example":"Accept, Accept-Encoding"},"description":"Required so caches key HTML vs markdown separately."}},"content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/api/newsletter":{"post":{"tags":["Newsletter"],"operationId":"subscribeNewsletter","summary":"Subscribe an email to the Sandwich newsletter","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"recaptchaToken":{"type":"string"}}}}}},"responses":{"200":{"description":"Subscription accepted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/ApiError"},"405":{"$ref":"#/components/responses/ApiError"},"429":{"$ref":"#/components/responses/ApiError"},"500":{"$ref":"#/components/responses/ApiError"}}}},"/api/auth/me":{"get":{"tags":["Auth"],"operationId":"getAuthMe","summary":"Current session identity","description":"Returns authenticated:false with HTTP 200 when no valid session cookie is present.","responses":{"200":{"description":"Session probe","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/auth/session":{"post":{"tags":["Auth"],"operationId":"createAuthSession","summary":"Mint a Sandwich session cookie from a Firebase ID token","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["idToken"],"properties":{"idToken":{"type":"string"}}}}}},"responses":{"200":{"description":"Session minted or token refresh required","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/ApiError"},"401":{"$ref":"#/components/responses/ApiError"},"500":{"$ref":"#/components/responses/ApiError"}}}},"/api/auth/signout":{"post":{"tags":["Auth"],"operationId":"signOutSession","summary":"Clear the Sandwich session cookie","responses":{"200":{"description":"Signed out","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/community":{"get":{"tags":["Community"],"operationId":"getCommunity","summary":"List community threads for a channel","parameters":[{"name":"channel","in":"query","required":true,"schema":{"type":"string"},"description":"Channel slug, e.g. medicaid"}],"responses":{"200":{"description":"Thread list","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/ApiError"},"404":{"$ref":"#/components/responses/ApiError"},"500":{"$ref":"#/components/responses/ApiError"}}},"post":{"tags":["Community"],"operationId":"postCommunity","summary":"Join a channel or create a thread/comment","security":[{"firebaseBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string"},"action":{"type":"string","enum":["join","leave","thread","comment"]}}}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/ApiError"},"401":{"$ref":"#/components/responses/ApiError"},"403":{"$ref":"#/components/responses/ApiError"},"404":{"$ref":"#/components/responses/ApiError"},"500":{"$ref":"#/components/responses/ApiError"}}}}},"components":{"securitySchemes":{"firebaseBearer":{"type":"http","scheme":"bearer","bearerFormat":"Firebase ID token","description":"Firebase ID token from a signed-in Sandwich user."}},"schemas":{"ApiError":{"type":"object","required":["error","code","message","hint"],"properties":{"error":{"type":"object","required":["code","message","hint"],"properties":{"code":{"type":"string","example":"NOT_FOUND"},"message":{"type":"string"},"hint":{"type":"string"}}},"code":{"type":"string","example":"NOT_FOUND"},"message":{"type":"string"},"hint":{"type":"string"}}},"OAuthAuthorizationServer":{"type":"object","required":["issuer","authorization_endpoint","token_endpoint","response_types_supported"],"properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"response_types_supported":{"type":"array","items":{"type":"string"}}}},"JsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"null"}]},"method":{"type":"string"},"params":{"type":"object","additionalProperties":true}}},"JsonRpcResponse":{"type":"object","required":["jsonrpc"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"null"}]},"result":{"type":"object","additionalProperties":true},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"},"data":{"type":"object","properties":{"hint":{"type":"string"}},"additionalProperties":true}}}}}},"responses":{"ApiError":{"description":"Structured JSON error with code, message, and resolution hint","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}