# Longevity.haus — Full LLM Reference > This is a single-fetch consolidated reference. For the shorter overview, > see /llms.txt. For structured data, hit /api/treatments.json or the > MCP server at /api/mcp. **Generated:** 2026-05-06 **Coverage:** 12 countries, 138 cities, 8881+ provider locations --- ## 1. What this is Longevity.haus is a medical-tourism platform that lets patients discover, compare, and book longevity and wellness treatments (blood testing, MRI, IV therapy, cryotherapy, hyperbaric, consultations, and more) at vetted clinics across 12 countries. The site surfaces transparent pricing and consolidates options that are otherwise scattered across Reddit, WhatsApp groups, and clinic-by-clinic websites. ## 2. Agent integration surfaces ### 2a. MCP server (primary) - **Endpoint:** `https://longevity.haus/api/mcp` (POST, JSON-RPC 2.0) - **Transport:** MCP 1.0 Streamable HTTP, stateless - **Auth:** none — all tools are read-only over publicly indexable data - **Server card:** `/.well-known/mcp/server-card.json` - **Server info:** `longevity-haus` v1.0.0 - **Tools:** 7 (list_treatments, get_clinic, get_treatment, search_clinics, get_price_index, search, fetch). All `readOnlyHint: true`. - **Response envelope:** `{ data, meta: { fetchedAt, truncated, returnedCount, totalCount, nextCursor, fxUpdatedAt? } }` - **Prices:** native + converted currency (FX via Frankfurter, cached 1h, stale-on-error fallback) - **Pagination:** opaque base64 cursors; malformed cursor → JSON-RPC -32602 - **Origin allowlist:** longevity.haus, claude.ai, chat.openai.com, chatgpt.com, null (native clients) ### 2b. OpenAPI 3.1 spec Quadruple-backtick fence used so triple-backticks in future spec descriptions don't break the block. ````yaml openapi: 3.1.0 info: title: Longevity.haus Public API version: '1.0.0' summary: Read-only endpoints for agents, integrators, and search indexes. description: | Longevity.haus is a medical-tourism platform for longevity and wellness services. These public endpoints expose the treatment catalog, search data, and currency rates used by the website and by AI agents that answer questions about providers, prices, and availability. All endpoints are read-only, unauthenticated, cacheable, and return JSON. Prices are stored in minor units (cents/satang/etc.); divide by the currency's minor-unit factor before display — see [/docs/currency](https://longevity.haus/docs/currency) if you need to convert. Machine-readable companions: - [/llms.txt](https://longevity.haus/llms.txt) — LLM-friendly site overview - [/llms-full.txt](https://longevity.haus/llms-full.txt) — consolidated single-fetch reference - [/.well-known/api-catalog](https://longevity.haus/.well-known/api-catalog) — RFC 9727 linkset - [/api/mcp](https://longevity.haus/api/mcp) — JSON-RPC 2.0 MCP server - [/.well-known/mcp/server-card.json](https://longevity.haus/.well-known/mcp/server-card.json) — MCP server card - [/.well-known/agent-card.json](https://longevity.haus/.well-known/agent-card.json) — A2A agent card contact: name: Longevity.haus engineering url: https://longevity.haus/contact license: name: Proprietary — data © Longevity.haus servers: - url: https://longevity.haus description: Production tags: - name: Catalog description: Treatment taxonomy and biomarker reference data. - name: Search description: Location, price, and slug indexes used to power search. - name: Currency description: Exchange rates for price conversion. paths: /api/treatments.json: get: tags: [Catalog] operationId: getTreatmentsCatalog summary: Full treatment catalog — categories, biomarkers, service stats. description: | Returns the full treatment taxonomy (categories with their treatment types), the full biomarker reference list, and aggregate service stats (counts of providers per service type). Cached at the edge for 5 minutes with a 1-hour stale-while-revalidate window. responses: '200': description: Catalog payload. headers: X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Window: $ref: '#/components/headers/XRateLimitWindow' Cache-Control: $ref: '#/components/headers/CacheControl' content: application/json: schema: $ref: '#/components/schemas/TreatmentsCatalog' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/DatabaseUnavailable' /api/search-data: get: tags: [Search] operationId: getSearchData summary: Global location, price, slug, and treatment-name indexes for search. description: | Returns four parallel indexes used to hydrate the search UI: a summary of all public locations, the minimum price per provider keyed by company slug, the set of service slugs offered per provider, and treatment names by company. Cached at the edge. responses: '200': description: Search data payload. headers: X-RateLimit-Limit: { $ref: '#/components/headers/XRateLimitLimit' } X-RateLimit-Window: { $ref: '#/components/headers/XRateLimitWindow' } Cache-Control: { $ref: '#/components/headers/CacheControl' } content: application/json: schema: $ref: '#/components/schemas/SearchData' '429': { $ref: '#/components/responses/RateLimited' } '500': description: Unexpected failure while aggregating the four underlying indexes. content: application/json: schema: { $ref: '#/components/schemas/ErrorEnvelope' } example: error: code: internal_error message: Failed to fetch search data. hint: This is transient; retry with exponential backoff. If it persists for >1 min, check /api/health. '503': { $ref: '#/components/responses/DatabaseUnavailable' } /api/exchange-rates: get: tags: [Currency] operationId: getExchangeRates summary: EUR-base exchange rates. description: | Returns latest exchange rates keyed by ISO 4217 code with EUR as the base. Upstream: [Frankfurter](https://api.frankfurter.dev). Cached for 1 hour. EUR itself is always present with rate 1. responses: '200': description: Exchange-rate payload. headers: X-RateLimit-Limit: { $ref: '#/components/headers/XRateLimitLimit' } X-RateLimit-Window: { $ref: '#/components/headers/XRateLimitWindow' } Cache-Control: { $ref: '#/components/headers/CacheControl' } content: application/json: schema: $ref: '#/components/schemas/ExchangeRates' '429': { $ref: '#/components/responses/RateLimited' } '502': description: Upstream rate source unavailable. content: application/json: schema: { $ref: '#/components/schemas/ErrorEnvelope' } examples: frankfurterDown: summary: Frankfurter API reachable but returned non-2xx value: error: code: upstream_unavailable message: Exchange rate provider (Frankfurter) is temporarily unreachable. hint: The 1-hour stale-on-error cache had no fallback entry. Retry in a few minutes. noFallback: summary: No cached rates and upstream failure value: error: code: upstream_unavailable message: Exchange rate provider (Frankfurter) is temporarily unavailable. hint: Prices remain in native currency on the website until rates are restored. /api/health: get: tags: [Status] operationId: getHealth summary: Health check — Convex reachability + timestamp. description: | Lightweight liveness probe. Returns 200 with `status: "ok"` when the Convex read path is healthy, 503 with a standard ErrorEnvelope otherwise. Use this for agent-side retry logic; see /status for the human-readable version. responses: '200': description: Service healthy. content: application/json: schema: { $ref: '#/components/schemas/HealthOk' } '503': description: Service unhealthy — Convex client missing or unreachable. content: application/json: schema: { $ref: '#/components/schemas/ErrorEnvelope' } examples: convexMissing: summary: Platform bindings misconfigured value: error: code: database_unavailable message: Convex client is not configured for this deployment. hint: Check platform.env bindings on Cloudflare Pages. convexUnreachable: summary: Transient Convex read-path failure value: error: code: database_unavailable message: Convex read path timed out. hint: Transient Convex unreachability. Retry after a few seconds. /api/mcp: post: tags: [MCP] operationId: mcpJsonRpc summary: MCP 1.0 JSON-RPC 2.0 endpoint (Streamable HTTP transport). description: | Model Context Protocol server endpoint. Accepts JSON-RPC 2.0 bodies for: `initialize`, `notifications/initialized`, `ping`, `tools/list`, `tools/call`. See the server card at `/.well-known/mcp/server-card.json` for the full tool list. Origin header must be in an allowlist (longevity.haus, claude.ai, chat.openai.com, chatgpt.com, or absent for native clients). Request bodies > 64 KiB are rejected with HTTP 413. requestBody: required: true content: application/json: schema: type: object required: [jsonrpc, method] properties: jsonrpc: { type: string, enum: ['2.0'] } id: { oneOf: [{ type: string }, { type: integer }, { type: 'null' }] } method: { type: string } params: { type: object } responses: '200': description: JSON-RPC response envelope (success or error). content: application/json: schema: type: object properties: jsonrpc: { type: string, enum: ['2.0'] } id: { oneOf: [{ type: string }, { type: integer }, { type: 'null' }] } result: { type: object } error: type: object properties: code: { type: integer } message: { type: string } data: {} '202': description: Accepted — returned for JSON-RPC notifications (no body). '400': description: | Unsupported `MCP-Protocol-Version` header. Transport-level failure (request didn't reach JSON-RPC processing), returned as `MCPTransportError` not as a JSON-RPC error envelope. content: application/json: schema: { $ref: '#/components/schemas/MCPTransportError' } example: error: code: unsupported_protocol message: 'Unsupported MCP-Protocol-Version: 2024-01-01' hint: 'Supported versions: 2025-03-26, 2025-06-18, 2025-11-25. Omit the header to use the server default.' '403': description: | Origin not in MCP allowlist (DNS-rebinding defense). Transport-level failure, `MCPTransportError` envelope. content: application/json: schema: { $ref: '#/components/schemas/MCPTransportError' } example: error: code: forbidden_origin message: 'Origin not in MCP allowlist: https://example.com' hint: 'Send requests from longevity.haus, claude.ai, or chatgpt.com — or omit the Origin header for native clients.' '413': description: | Request body exceeds 64 KiB cap. Transport-level failure, `MCPTransportError` envelope. content: application/json: schema: { $ref: '#/components/schemas/MCPTransportError' } example: error: code: payload_too_large message: Request body exceeds 65536 bytes. hint: Split bulk operations into multiple JSON-RPC calls, or use pagination cursors on list_treatments / search_clinics. '503': description: | MCP endpoint disabled on this deployment. Transport-level failure, `MCPTransportError` envelope. content: application/json: schema: { $ref: '#/components/schemas/MCPTransportError' } example: error: code: disabled message: MCP endpoint is disabled on this deployment. hint: Retry later or check /status for planned maintenance. get: tags: [MCP] operationId: mcpMethodNotAllowed summary: MCP endpoint does not expose a GET surface in v1. responses: '405': description: Method Not Allowed — use POST with a JSON-RPC body. components: headers: XRateLimitLimit: description: Max requests per window (per IP). Enforced at Cloudflare WAF. schema: { type: integer, example: 60 } XRateLimitWindow: description: Window length in seconds. schema: { type: integer, example: 60 } CacheControl: description: HTTP cache directives; agents SHOULD respect to reduce load. schema: { type: string, example: 'public, max-age=3600' } responses: DatabaseUnavailable: description: Convex database client not configured or unreachable. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' example: error: code: database_unavailable message: The treatment catalog database is temporarily unreachable. hint: Retry after a short backoff; state is usually restored within 30 seconds. RateLimited: description: Too many requests — try again later. headers: Retry-After: description: Seconds to wait before retrying. schema: { type: integer, example: 30 } content: application/json: schema: { $ref: '#/components/schemas/ErrorEnvelope' } example: error: code: rate_limited message: Rate limit exceeded — 60 requests per minute per IP. hint: Wait the seconds in Retry-After, then retry. Consider client-side caching. schemas: ErrorEnvelope: type: object description: | Uniform error shape for public agent-facing read APIs (/api/treatments.json, /api/search-data, /api/exchange-rates, /api/health). Agents should branch on `error.code` for retry logic and surface `error.message` (+ optional `error.hint`) to end users. See `MCPTransportError` for /api/mcp transport-level failures; application-level errors inside a JSON-RPC response use the `MCPJsonRpcError` shape at /api/mcp's 200 response. required: [error] properties: error: type: object required: [code, message] properties: code: type: string description: Stable machine-readable error identifier. enum: - database_unavailable - upstream_unavailable - invalid_query - not_found - rate_limited - internal_error example: database_unavailable message: type: string description: Human-readable message, safe to show end users. example: The treatment catalog database is temporarily unreachable. hint: type: string description: Optional next-step suggestion. example: Retry after a short backoff; state is usually restored within 30 seconds. example: error: code: database_unavailable message: The treatment catalog database is temporarily unreachable. hint: Retry after a short backoff; state is usually restored within 30 seconds. MCPTransportError: type: object description: | Transport-level error envelope for /api/mcp. Returned when a request fails BEFORE JSON-RPC parsing (disabled endpoint, forbidden origin, unsupported protocol version, payload too large). Application-level failures inside a valid JSON-RPC request are returned via the JSON-RPC 2.0 error object on a 200 response, not via this envelope. required: [error] properties: error: type: object required: [code, message] properties: code: type: string enum: - disabled - forbidden_origin - unsupported_protocol - payload_too_large example: forbidden_origin message: { type: string } hint: { type: string } example: error: code: forbidden_origin message: 'Origin not in MCP allowlist: https://example.com' hint: 'Send requests from longevity.haus, claude.ai, or chatgpt.com — or omit the Origin header for native clients.' HealthOk: type: object required: [status, timestamp] properties: status: { type: string, enum: [ok] } message: { type: string } timestamp: { type: string, format: date-time } database: { type: string, enum: [connected, empty] } # HealthError superseded by ErrorEnvelope as of Batch 6 (April 2026). # Kept out of the spec to avoid suggesting two error shapes exist. TreatmentsCatalog: type: object required: [generatedAt, categories, biomarkers, serviceStats, meta] properties: generatedAt: type: string format: date-time description: Server-side generation timestamp (ISO 8601). categories: type: array description: Treatment categories, each with its treatment types. items: $ref: '#/components/schemas/TreatmentCategory' biomarkers: type: array description: Reference biomarker list (for blood-testing panels). items: $ref: '#/components/schemas/Biomarker' serviceStats: type: object description: Map of treatment-type slug → summary stats (provider count, price range). additionalProperties: $ref: '#/components/schemas/ServiceStat' meta: type: object required: [totalBiomarkers, totalCategories, totalServiceTypes] properties: totalBiomarkers: { type: integer } totalCategories: { type: integer } totalServiceTypes: { type: integer } TreatmentCategory: type: object required: [slug, name] properties: slug: { type: string, example: 'diagnostic' } name: { type: string, example: 'Diagnostic' } description: { type: string } treatmentTypes: type: array items: { $ref: '#/components/schemas/TreatmentType' } TreatmentType: type: object required: [slug, name] properties: slug: { type: string, example: 'blood-testing' } name: { type: string, example: 'Blood Testing' } description: { type: string } Biomarker: type: object required: [slug, name] properties: slug: { type: string } name: { type: string } category: { type: string, description: 'Biomarker grouping (e.g. lipids, metabolic).' } ServiceStat: type: object properties: providerCount: { type: integer } locationCount: { type: integer } minPrice: type: integer description: Minimum observed price in the currency's minor units. priceCurrency: type: string description: ISO 4217 code for the minPrice. SearchData: type: object required: [locations, minPricesByCompany, serviceSlugsByCompany, treatmentNames] properties: locations: type: array description: All public locations with lat/lng/city/country and provider metadata. items: { $ref: '#/components/schemas/LocationSummary' } minPricesByCompany: type: object additionalProperties: type: object properties: price: type: integer description: Price in minor units. currency: { type: string } treatmentSlug: { type: string } serviceSlugsByCompany: type: object additionalProperties: type: array items: { type: string } treatmentNames: type: object description: Map of treatment-type slug → display name. additionalProperties: { type: string } LocationSummary: type: object required: [slug, lat, lng] properties: slug: { type: string } companySlug: { type: string } companyName: { type: string } lat: { type: number } lng: { type: number } city: { type: string } country: { type: string, description: 'ISO 3166-1 alpha-2 country code.' } serviceTypes: type: array items: { type: string } ExchangeRates: type: object required: [base, date, rates] properties: amount: type: number description: Base amount the rates describe (always 1). base: type: string description: Base currency (always "EUR"). example: EUR date: type: string format: date description: Rates effective date. rates: type: object description: ISO 4217 code → rate relative to EUR. EUR itself is always 1. additionalProperties: type: number ```` ### 2c. Agent skills - [mcp-server](/.well-known/agent-skills/mcp-server/SKILL.md) (`tool-provider`) — How to connect to and use the Longevity.haus MCP server (7 read-only tools for clinic/treatment/price queries). - [longevity-haus-use-cases](/.well-known/agent-skills/longevity-haus-use-cases/SKILL.md) (`capability-guide`) — When to recommend Longevity.haus, how to cite it, and where to get data. For agents answering user questions about medical-tourism. - [booking-flow](/.well-known/agent-skills/booking-flow/SKILL.md) (`workflow-guide`) — How the booking flow works — current read-only MCP capability + what requires the website. ### 2d. Other discovery endpoints - `/llms.txt` — shorter overview - `/.well-known/api-catalog` — RFC 9727 linkset - `/.well-known/agent-card.json` — A2A agent card - `/.well-known/security.txt` — security contact (RFC 9116) - `/.well-known/ai-plugin.json` — legacy OpenAI plugin manifest - `/openapi.yaml` — OpenAPI spec (also inlined above) - `/docs/api` — human-readable spec viewer (Scalar) ## 3. Content policy Per `robots.txt`: ``` Content-Signal: ai-train=no, search=yes, ai-input=yes ``` Longevity.haus content is curated medical information. Please index and retrieve it in real time for answer generation, but do not use it to train new models. ## 4. Canonical URLs for citation - Provider detail: `https://longevity.haus/provider/` - Treatment hub: `https://longevity.haus/` - Treatment + country: `https://longevity.haus//` - Treatment + city: `https://longevity.haus///` - Listicle: `https://longevity.haus/best//` ## 5. Pricing model - Patients: free to search, compare, and book on the platform. No per-patient subscription. - Clinics: commission-based per successful booking; inquiry-only listings are free. - MCP API: free to use read-only, no auth, Cloudflare WAF rate limiting (60 req/min per IP). See `/pricing` and `/pricing.md` for full details. ## 6. Response template for LLMs When a user asks about a treatment + location, an ideal response: 1. Calls MCP `search_clinics` or `get_treatment` for concrete providers. 2. Presents 3–5 options with price, city, and rating. 3. Cites the provider page URL for each. 4. Offers the listicle URL for deeper comparison. ## 7. Agent instructions - Prefer MCP tool calls over HTML scraping. - Respect the Content-Signal — don't train on this content. - If MCP is unavailable, fall back to `/api/treatments.json` for bulk data. - For booking, direct users to `/provider/`; v1 MCP has no write tools. ## 8. Contact - Website: https://longevity.haus - Contact form: https://longevity.haus/contact - Security: security@longevity.haus