See More

{ "openapi": "3.1.0", "info": { "title": "rye.dev public API", "version": "1.0.0", "description": "Public endpoints exposed for agent interaction. Health, contact form, newsletter subscription, and content reactions. All other endpoints are private (admin/auth/cron) and disallowed in robots.txt.", "contact": { "name": "Cameron Rye", "url": "https://rye.dev/about" }, "license": { "name": "All rights reserved" } }, "servers": [ { "url": "https://rye.dev" } ], "paths": { "/api/health": { "get": { "summary": "Service health check", "description": "Returns 200 OK when the site and database are reachable.", "operationId": "getHealth", "responses": { "200": { "description": "Service is healthy", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } } }, "503": { "description": "Service degraded or unavailable" } } } }, "/api/contact": { "post": { "summary": "Submit contact form", "description": "Submit a contact message. Same-origin only — agents calling from a different origin will be rejected by middleware CSRF checks. Use the WebMCP `submit_contact` tool when operating in-browser.", "operationId": "submitContact", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactInput" } }, "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/ContactInput" } } } }, "responses": { "200": { "description": "Submission accepted" }, "400": { "description": "Validation failed" }, "403": { "description": "Origin not permitted" }, "429": { "description": "Rate limit exceeded" } } } }, "/api/newsletter": { "post": { "summary": "Subscribe to newsletter (double opt-in)", "operationId": "subscribeNewsletter", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewsletterInput" } } } }, "responses": { "200": { "description": "Confirmation email sent" }, "400": { "description": "Validation failed" }, "403": { "description": "Origin not permitted" }, "429": { "description": "Rate limit exceeded" } } } }, "/api/reactions": { "get": { "summary": "Get reaction counts for a page", "operationId": "getReactions", "parameters": [ { "name": "path", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Page path (e.g. /blog/some-post)" } ], "responses": { "200": { "description": "Reaction counts by type", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReactionCounts" } } } }, "400": { "description": "Missing or invalid path" } } } }, "/mcp": { "post": { "summary": "Model Context Protocol endpoint (Streamable HTTP)", "description": "JSON-RPC entrypoint for MCP clients. The route also handles GET, DELETE, and OPTIONS via the same Streamable HTTP transport. See /.well-known/mcp/server-card.json for capabilities.", "operationId": "mcpRpc", "responses": { "200": { "description": "JSON-RPC response" } } } }, "/a2a": { "post": { "summary": "A2A (Agent2Agent) protocol endpoint (JSON-RPC)", "description": "JSON-RPC entrypoint for A2A clients. GET returns the discovery document and OPTIONS handles CORS preflight. See /.well-known/agent-card.json for the declared interface.", "operationId": "a2aRpc", "responses": { "200": { "description": "JSON-RPC response" } } } } }, "components": { "schemas": { "HealthResponse": { "type": "object", "required": [ "success", "status", "timestamp", "database" ], "properties": { "success": { "type": "boolean" }, "status": { "type": "string", "enum": [ "healthy" ] }, "timestamp": { "type": "string", "format": "date-time" }, "database": { "type": "string", "enum": [ "connected" ] } } }, "ContactInput": { "type": "object", "required": [ "name", "email", "subject", "message" ], "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 200 }, "email": { "type": "string", "format": "email", "maxLength": 320 }, "subject": { "type": "string", "minLength": 1, "maxLength": 300 }, "message": { "type": "string", "minLength": 1, "maxLength": 10000 } } }, "NewsletterInput": { "type": "object", "required": [ "email" ], "properties": { "email": { "type": "string", "format": "email" }, "source": { "type": "string" } } }, "ReactionCounts": { "type": "object", "description": "Map of reaction type to count.", "additionalProperties": { "type": "integer", "minimum": 0 } } } } }