{"openapi":"3.1.0","info":{"title":"Durate website API","version":"1.0.0","summary":"Public HTTP surface of www.durate.com.","description":"Durate is AI physician scheduling software for hospitals and physician groups. This spec covers the marketing site: a contact endpoint, a get-started signup, an MCP server (Streamable HTTP), and machine-readable site indexes (llms.txt, llms-full.txt, sitemap.xml). It does not cover the Durate product itself; for product questions email contact@durate.com. All error responses are structured JSON with a code, message, and resolution hint. Versioning: the API is additive-only version 1, reported by the X-Api-Version response header on JSON endpoints; a breaking change would ship under new /api/v2/* paths, with the existing paths kept working. Rate limiting: 60 requests per 60s per client, self-reported on every response via the IETF RateLimit headers (RateLimit-Policy and RateLimit structured fields, plus the legacy RateLimit-Limit/-Remaining/-Reset trio); a 429 carries Retry-After. Developer overview: https://www.durate.com/developers.","contact":{"name":"Durate","email":"contact@durate.com","url":"https://www.durate.com/contact"}},"servers":[{"url":"https://www.durate.com"}],"paths":{"/api":{"get":{"operationId":"getApiIndex","summary":"API index","description":"Machine-readable list of every endpoint, for agents that land on /api.","responses":{"200":{"description":"Index of endpoints.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["name","openapi","endpoints"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"openapi":{"type":"string","format":"uri"},"endpoints":{"type":"array","items":{"type":"object","required":["method","path","description"],"properties":{"method":{"type":"string"},"path":{"type":"string"},"description":{"type":"string"}}}},"contact":{"type":"string","format":"email"}}}}}},"429":{"description":"Rate limit exceeded (60 requests per 60s per client). Honor Retry-After before retrying.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying (RFC 9110).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/contact":{"post":{"operationId":"sendContactMessage","summary":"Send a message to the Durate team","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["firstName","lastName","email"],"properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"phoneNumber":{"type":"string"},"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Message delivered.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Missing required field or invalid JSON body.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Only POST is accepted.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (60 requests per 60s per client). Honor Retry-After before retrying.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying (RFC 9110).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Delivery failed upstream; retry or email contact@durate.com.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/discord-webhook":{"post":{"operationId":"sendGetStartedSignup","summary":"Get-started signup","description":"Used by the site’s \"Get started\" forms: email plus optional message and referrer.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"message":{"type":"string"},"referrer":{"type":"string"}}}}}},"responses":{"200":{"description":"Signup delivered.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Missing email or invalid JSON body.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Only POST is accepted.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (60 requests per 60s per client). Honor Retry-After before retrying.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying (RFC 9110).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Delivery failed upstream; retry or email contact@durate.com.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/mcp":{"post":{"operationId":"mcp","summary":"MCP server (Streamable HTTP)","description":"Model Context Protocol endpoint (JSON-RPC 2.0 over Streamable HTTP, stateless). Protocol revisions 2025-11-25 through 2024-11-05. Supports initialize, ping, resources/list, resources/read, and resources/templates/list. Exposed resources: llms.txt, llms-full.txt, openapi.json, sitemap.xml. Also reachable at /mcp. No authentication required; the server is read-only. Server card (SEP-1649 discovery manifest): /.well-known/mcp.json.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"A JSON-RPC 2.0 request, notification, or batch."}}}},"responses":{"200":{"description":"JSON-RPC 2.0 response (or an array of them for a batch).","content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","id"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"null"}]},"result":{"type":"object","description":"Present on success."},"error":{"type":"object","required":["code","message"],"description":"Present on failure.","properties":{"code":{"type":"integer"},"message":{"type":"string"},"data":{}}}}}}}},"202":{"description":"Notification accepted (no body)."},"400":{"description":"JSON-RPC parse or protocol error.","content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","id"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"null"}]},"result":{"type":"object","description":"Present on success."},"error":{"type":"object","required":["code","message"],"description":"Present on failure.","properties":{"code":{"type":"integer"},"message":{"type":"string"},"data":{}}}}}}}},"429":{"description":"Rate limit exceeded (60 requests per 60s per client). Honor Retry-After before retrying.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying (RFC 9110).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/page-markdown":{"get":{"operationId":"getPageMarkdown","summary":"Markdown representation of a page","description":"Returns the markdown version of any site page, extracted from llms-full.txt. Agents normally reach this via content negotiation: request the page itself with Accept: text/markdown (acceptmarkdown.com convention) and the site rewrites here.","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string"},"description":"Site path of the page, e.g. /about or /customers/brown-health."}],"responses":{"200":{"description":"Markdown for the page.","content":{"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"The path is not a page on this site.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (60 requests per 60s per client). Honor Retry-After before retrying.","headers":{"X-Api-Version":{"description":"API version that produced this response (currently 1).","schema":{"type":"string"}},"RateLimit-Policy":{"description":"Rate-limit policy as an HTTP structured field, e.g. \"default\";q=60;w=60 (quota q per window of w seconds, per client).","schema":{"type":"string"}},"RateLimit":{"description":"Current state of the policy as a structured field: r=remaining requests, t=seconds until the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Legacy form: requests allowed per window.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"Legacy form: requests remaining in the current window.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"Legacy form: seconds until the current window resets.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying (RFC 9110).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/.well-known/mcp.json":{"get":{"operationId":"getMcpServerCard","summary":"MCP server card (discovery manifest)","description":"Static SEP-1649-style server card describing the MCP server: identity, protocol revision, streamable-http endpoint, capabilities, and the resource list. Fetch this to discover the server without a handshake.","responses":{"200":{"description":"The server card.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiSpec","summary":"This document","responses":{"200":{"description":"OpenAPI 3.1 specification.","content":{"application/json":{"schema":{"type":"object","required":["openapi","info","paths"],"properties":{"openapi":{"type":"string"},"info":{"type":"object"},"servers":{"type":"array","items":{"type":"object"}},"paths":{"type":"object"},"components":{"type":"object"}}}}}}}}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","summary":"llms.txt site index for AI agents","description":"Follows the llmstxt.org convention: what Durate is, key facts, and a link per page.","responses":{"200":{"description":"Markdown index of the site.","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/llms-full.txt":{"get":{"operationId":"getLlmsFullTxt","summary":"Full site content in one markdown file","responses":{"200":{"description":"Markdown dump of all page content.","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/sitemap.xml":{"get":{"operationId":"getSitemap","summary":"XML sitemap","responses":{"200":{"description":"Sitemap of every indexable page.","content":{"application/xml":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["invalid_json","missing_field","upstream_error","method_not_allowed","not_found","rate_limited"],"description":"Machine-readable error code."},"message":{"type":"string","description":"Human-readable description of what went wrong."},"hint":{"type":"string","description":"How to fix the request or where to look next."}}}}}}}}