{"openapi":"3.1.0","info":{"title":"Hormonaly Partner API","version":"2.0.0","description":"AI-powered hormonal health evidence API for partners. The Partner API\nis served under `/api/v1/` and comprises two service groups:\n\n- **Helix** (`/api/v1/helix/`) -- clinical evidence queries, compound\n  dossiers, head-to-head comparisons, and protocol lookups.\n- **Scribe** (`/api/v1/scribe/`) -- AI-generated clinical notes from\n  protocol selections.\n  \n  ## Authentication\nAll authenticated endpoints require a Bearer token obtained from the\npartner portal.  Tokens are prefixed `hk_live_` for production and\n`hk_test_` for sandbox.\n\n```\nAuthorization: Bearer hk_live_abc123...\n```\n\n## Rate Limiting\nEvery authenticated response includes rate-limit headers:\n\n| Header | Description |\n|--------|-------------|\n| `X-RateLimit-Limit` | Maximum requests per minute for your partner account |\n| `X-RateLimit-Remaining` | Requests remaining in the current window |\n| `X-RateLimit-Reset` | ISO-8601 timestamp when the window resets |\n| `Retry-After` | Seconds to wait (only on 429 responses) |\n\n## Tiers\nTier keys are `starter`, `professional` (sold as \"API Advanced\") and\n`enterprise`. Only two operations are tier-gated:\n\n| Tier | Query / Protocols / Usage / Status / Jobs | Dossier | Compare | Scribe |\n|------|------|---------|---------|--------|\n| Starter | Yes | No (`403 tier_insufficient`) | No (`403 tier_insufficient`) | Yes |\n| Professional (Advanced) | Yes | Yes | Yes | Yes |\n| Enterprise | Yes | Yes | Yes | Yes |\n\nReading a dossier (`GET /helix/dossier/{jobId}`, `/pdf`) is not gated.\nTiers otherwise govern volume: the per-partner rate limit and the monthly\ntoken budget. A partner's `allowed_endpoints` allowlist, when set, can\nadditionally restrict any path (`403 endpoint_not_allowed`).\n\n## Version headers\nEvery response from the Helix, Scribe and Evidence routers carries\n`X-API-Version` (this document's `info.version`) and `X-Model-Version`\n(the model serving `detail_level=clinical`). Neither is set on the\nunauthenticated `/health` and `/ping` probes or on `/api/v2/*`.\n\n## Models\nRequests are served by Google Gemini models on Vertex AI, selected by\n`detail_level`:\n\n| `detail_level` | Model | Notes |\n|----------------|-------|-------|\n| `clinical` (default) | Gemini 2.5 Pro | Reasoning-heavy clinical work. Runs with a thinking budget set per request by an internal effort level; the budget is added on top of the answer budget, so reasoning never truncates the answer. |\n| `summary` | Gemini 2.5 Flash | Fast path for shorter answers. Minimal thinking budget. |\n\nRetrieval reranking uses the Vertex AI Ranking API (a Google-served\ncross-encoder), with Gemini 2.5 Flash-Lite as the fallback tier; Flash-Lite\nalso serves the input safety classifier, extraction and other internal\nsub-calls. Since September 2026 the platform runs on Google only: if the\ntier head is unavailable the request falls back to another Gemini model\n(Pro ↔ Flash) and never to a non-Google vendor. A request that no Gemini\nmodel can serve fails with the standard error envelope rather than being\nanswered elsewhere.\n\nTwo behaviours worth noting if you are comparing outputs across releases:\n\n- **No sampling controls are exposed.** The API does not accept\n  `temperature` / `top_p` / `top_k`, and repeated identical requests are\n  not guaranteed byte-identical — compare on structure and citations.\n- **Reasoning traces are summarized.** Where an endpoint returns a\n  reasoning trace, it is the model's thought summary. The raw chain of\n  thought is never returned.\n\nThe active model id is returned on every response in the `X-Model-Version`\nheader and on `GET /helix/health`. Both are derived from the live router, so\nthey always name the model that actually served the request — use them for\ndrift detection rather than pinning to a value in this document. On\n`/helix/query`, `X-Helix-Model` names the model that produced the answer\nand `X-Helix-Model-Fallback: true` flags a within-Google fallback.\n\n## Response Envelope\nHelix, Scribe and `/api/v2/` endpoints return a consistent JSON envelope\n(`GET /evidence` and `GET /evidence/{id}` return the bare array / object\ndescribed on those operations, and the authentication, budget and\nrate-limit rejections emitted by the middleware carry `error` + `message`\nwithout a `success` key):\n\n**Success:**\n```json\n{\n  \"success\": true,\n  \"data\": { },\n  \"meta\": { }\n}\n```\n\n**Error:**\n```json\n{\n  \"success\": false,\n  \"error\": \"machine_readable_code\",\n  \"message\": \"Human-readable description\"\n}\n```\n\nLegacy endpoints at `/api/protocols`, `/api/categories`, and\n`/api/tools/interaction-checker` do **not** use this envelope.\nUse the `/api/v2/` equivalents for consistent responses.\nSee `docs/api-versioning.md` for the full versioning policy.\n\n## Error Handling\nAll errors follow a consistent JSON envelope with `success: false` and\nan `error` machine-readable code.  See the `ErrorResponse` schema.\n\n## Webhooks\nPartners with a webhook URL configured on their account receive a\n`job.completed` event when an async job submitted via `POST /helix/jobs`\nfinishes (sent for both `done` and `failed` outcomes). Dossier jobs\n(`POST /helix/dossier`) do **not** emit webhooks — poll\n`GET /helix/dossier/{jobId}` instead.\n\nDeliveries are HTTPS POSTs carrying `X-Hormonaly-Job-Id` (for dedup)\nand, when a signing secret is configured, three signature headers:\n`X-Hormonaly-Signature-V2` (`t=<unix-seconds>,v1=<hex>`, HMAC-SHA256 of\n`${t}.${rawBody}` — verify this one and reject timestamps outside a\n±5 minute window), `X-Hormonaly-Timestamp` (the same `t`) and the\noriginal body-only `X-Hormonaly-Signature` (`sha256=<hex>`, kept for\nexisting verifiers). Up to 4 attempts with backoff (1 s / 8 s / 64 s) on\nnon-2xx, network error, or 10 s timeout, each attempt signed with its own\ntimestamp; redirects are never followed. Webhook URL and secret are\nconfigured by the Hormonaly team on request. See the `jobCompleted`\nentry under `webhooks`.\n\nThe same URL and signature scheme also receive `usage.threshold_reached`\nwhen your account passes 80% and 100% of the tokens included in your\nplan, and when it reaches the enforced monthly cap (after which live keys\nreceive `429 monthly_budget_exceeded` until the 1st). Each is sent at\nmost once per calendar month, with a copy by email to your contact and\nbilling addresses. See `usageThresholdReached` under `webhooks`.\n\n## Monthly token cap\nThe enforced cap is the tighter of the cap configured on your account\nand your plan's hard cap (Starter 10M, Advanced 75M, Enterprise none).\n`X-Token-Budget-Limit` on every response is that number.\n","contact":{"name":"Helix API Support","email":"info@hormonaly.ai"},"license":{"name":"Proprietary"}},"servers":[{"url":"/api/v1","description":"Production (v1)"},{"url":"/api/v2","description":"Production (v2 — envelope-normalised catalog and tool endpoints)"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Helix","description":"Clinical evidence engine endpoints"},{"name":"Scribe","description":"AI clinical note generation"},{"name":"Jobs","description":"Async long-job polling (Phase A)"},{"name":"Catalog","description":"Protocol and category catalog (v2 envelope-wrapped)"},{"name":"Tools","description":"Clinical tool endpoints (v2 envelope-wrapped)"},{"name":"Health","description":"Unauthenticated health-check endpoints"},{"name":"Evidence","description":"Evidence library catalog (allowlist-gated)"}],"paths":{"/helix/health":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixHealth","summary":"Helix health check","description":"Liveness, plus operational diagnostics for authenticated callers.\n\nNo authentication is required, but the response has two shapes. Without\na valid partner key you get liveness only — `status`, `service`,\n`version`, `timestamp`. Present a valid `Authorization: Bearer` key and\nthe same payload also carries uptime, capabilities, the live model ids\nand the server's request deadlines.\n\nThis endpoint always returns 200, including for a key that is invalid,\nexpired or over budget: a lapsed subscription must not turn a partner's\nmonitoring red, and health must not become an oracle for testing key\nvalidity. Rate-limit headers are NOT emitted here — health runs ahead of\nthe rate limiter.\n","tags":["Health"],"security":[],"responses":{"200":{"description":"Service is live. Diagnostic fields present only when a valid partner key was supplied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixHealthResponse"},"examples":{"unauthenticated":{"summary":"No key — liveness only","value":{"status":"ok","service":"helix-api","version":"2.0.0","timestamp":"2026-04-05T12:00:00.000Z"}},"authenticated":{"summary":"Valid partner key — full diagnostics","value":{"status":"ok","service":"helix-api","version":"2.0.0","timestamp":"2026-04-05T12:00:00.000Z","uptime_seconds":86400,"capabilities":["query","dossier","compare","protocols"],"recommended_timeout_ms":100000,"recommended_stream_timeout_ms":155000,"timeouts_ms":{"query_hard":95000,"stream_hard":150000,"stream_stall":30000},"models":{"clinical":"gemini-2.5-pro","summary":"gemini-2.5-flash"}}}}}}}}}},"/helix/openapi.json":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixOpenApiSpec","summary":"Fetch the OpenAPI document","description":"Returns this specification as JSON, for code generators, Prism mock\nservers and Postman imports.\n\nThe unauthenticated public copy at `/api/v1/openapi.json` imports\nwithout a key; this authenticated copy is the one to generate an SDK\nagainst when your key has partner-specific endpoints enabled.\n","tags":["Health"],"responses":{"200":{"description":"The OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object","description":"An OpenAPI 3.1 document."}}}}}}},"/helix/ping":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixPing","summary":"Helix ping","description":"Lightweight liveness probe. No authentication required.","tags":["Health"],"security":[],"responses":{"200":{"description":"Pong.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"ts":{"type":"integer","description":"Unix timestamp in milliseconds."}}},"example":{"ok":true,"ts":1743868800000}}}}}}},"/helix/query":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"post":{"operationId":"postHelixQuery","summary":"Clinical evidence query","description":"Ask a clinical question and receive an AI-synthesized, evidence-based\nanswer with optional citations and three-lens scoring.\n\n**Recommended client timeout:** 100 seconds for buffered requests\n(`recommended_timeout_ms` on `GET /helix/health`, derived from the\n95 s `query_hard` ceiling) and 155 seconds for streams. Use\n`detail_level=summary` for materially faster responses.\n\n**Streaming (SSE).** Send `stream: true` in the body or\n`Accept: text/event-stream` to receive progressive Server-Sent Events\n(first paint ~1–2 s vs 5–12 s buffered). Event sequence:\n`stage` (pipeline milestone) → `agent` (routed intent) → `sources`\n(retrieval counts) → repeated `content` (answer deltas) → an optional\nsingle `content_replace` (the server-corrected authoritative text, after\ncitation gating, reference rebind and the claim-by-claim support check)\n→ `done` (grade, confidence, citations, evidence, citation_check,\nrelated_protocols, agent_attributions, usage). `heartbeat`\nevents keep the connection alive; an `error` event signals failure. The\n`done` payload carries the same fields as the buffered `data` object.\nFor `detail_level=clinical` answers the first `content` deltas are the\nanswer's opening `## Bottom line` paragraph, written by a fast model,\nand the rest of the answer follows it. `done` may carry an optional\n`generation` object (`bottom_line_first`, `body_model`: `deep` or\n`fast`, `body_reason`); clients that do not read it are unaffected. `citations` lists every PMID the final answer cites,\nso each `claims[].pmids` entry resolves to a citation, and each\ncitation's `id` is the number of its `[N]` marker. Every citation\ncarries its `evidence_level` and publication `year`; the `evidence`\nobject gives the answer's evidence strength and an `as_of` date, and\n`citation_check` reports how many cited sentences were verified\nagainst their source (unsupported markers are moved or removed, and a\nsentence left stating a figure with no supporting source is removed).\n","tags":["Helix"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixQueryRequest"},"example":{"question":"What is the evidence for BPC-157 in tendon repair?","language":"en","detail_level":"clinical","include_citations":true,"include_three_lens":false,"bypass_cache":false}}}},"responses":{"200":{"description":"Successful evidence response.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Helix-Response-Time":{"$ref":"#/components/headers/X-Helix-Response-Time"},"X-Helix-Cache":{"$ref":"#/components/headers/X-Helix-Cache"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixQueryResponse"},"example":{"success":true,"data":{"answer":"BPC-157 (Body Protection Compound-157) has shown promising results...","agents_used":["compound_research"],"agent_attributions":[{"agent":"Compound Research","contribution":"BPC-157 is a pentadecapeptide with emerging evidence..."}],"confidence":{"score":0.72,"level":"moderate","factors":["Grade B evidence","3 citations"]},"grade":"B","recommendation":null,"related_protocols":[{"id":"bpc-157","title":"BPC-157 Protocol","category":"peptides","evidence_level":"moderate","grade":"B"}],"citations":[{"id":1,"pmid":"12345678","source":"https://pubmed.ncbi.nlm.nih.gov/12345678","citation_type":"pmid","year":2024,"evidence_level":"rct","publication_types":["Journal Article","Randomized Controlled Trial"],"verification":"verified"}],"evidence":{"as_of":"2026-09-28","corpus_version":412,"corpus_updated_at":"2026-09-27T03:31:12.000Z","evidence_checked_at":"2026-09-28T03:30:40.000Z","live_literature_search":true,"live_literature_searched_at":"2026-09-28T14:02:11.000Z","newest_source_year":2025,"strength":"moderate","summary":"Moderate evidence: 1 guideline/systematic review/RCT source among 3 on-topic.","levels":{"rct":1,"observational":2}},"citation_check":{"checked":6,"supported":5,"reanchored":0,"dropped":1,"removed_sentences":0,"unclear":0,"overstated":1,"mismatch_types":{"population":1,"causal_language":1}}},"usage":{"tokens":1850,"latency_ms":8230,"quality_retries":0}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/IdempotencyKeyReuseMismatch"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"The model returned an empty response (safety stop or truncation). Retry, or rephrase the question.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"empty_response","message":"Helix could not generate a response for this query. Please retry or rephrase."}}}},"503":{"description":"Your organization's published policy could not be loaded, so the request was refused rather than answered without it. Retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"policy_unavailable","message":"Your organization's policy could not be loaded; the request was not answered. Retry shortly."}}}},"504":{"description":"Gateway timeout -- the AI model took too long.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"gateway_timeout","message":"Helix took too long to respond. Set your client timeout to at least 100s, opt into streaming (Accept: text/event-stream, up to 155s), or retry with detail_level=summary.","retry_with":{"detail_level":"summary","stream":true}}}}}}}},"/helix/dossier":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"post":{"operationId":"postHelixDossier","summary":"Generate compound dossier","description":"Start asynchronous generation of a comprehensive evidence dossier for\na compound. Returns a `job_id` to poll via `GET /helix/dossier/{jobId}`.\n\n**Tier requirement:** Advanced (`professional`) or Enterprise. Starter\nkeys receive `403 tier_insufficient`.\n\n**Organization policy:** applied after the safety gate, before any\ngeneration or billing. Every named compound must be permitted by your\npublished policy; otherwise the request is refused with HTTP 200,\n`blocked: true`, `block_reason: \"tenant_policy\"` and `data.policy`\n`{ version, reason, terms }`, not billed.\n","tags":["Helix"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixDossierRequest"},"example":{"compound":"Testosterone Cypionate","language":"en"}}}},"responses":{"200":{"description":"Dossier generation started.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixDossierJobCreatedResponse"},"example":{"success":true,"data":{"job_id":"dossier_1743868800000_a1b2c3d4e5f6","status":"processing","compound":"Testosterone Cypionate","estimated_seconds":45,"poll_url":"/api/v1/helix/dossier/dossier_1743868800000_a1b2c3d4e5f6"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"Your organization's published policy could not be loaded, so the request was refused rather than processed without it. Retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"policy_unavailable","message":"Your organization's policy could not be loaded; the request was not processed. Retry shortly."}}}}}}},"/helix/dossier/{jobId}":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixDossierJob","summary":"Poll dossier job status","description":"Poll an in-progress dossier job or retrieve a completed dossier by its\njob ID or dossier ID.\n","tags":["Helix"],"parameters":[{"name":"jobId","in":"path","required":true,"description":"The job ID returned by `POST /helix/dossier`, or a dossier ID.","schema":{"type":"string"}}],"responses":{"200":{"description":"Job status. Shape varies by `status` field.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/DossierJobProcessingResponse"},{"$ref":"#/components/schemas/DossierJobCompletedResponse"},{"$ref":"#/components/schemas/DossierJobFailedResponse"}]},"examples":{"processing":{"summary":"Job still processing","value":{"success":true,"data":{"job_id":"dossier_1743868800000_a1b2c3d4e5f6","status":"processing","compound":"Testosterone Cypionate","elapsed_seconds":12,"estimated_remaining":33}}},"completed":{"summary":"Job completed","value":{"success":true,"data":{"job_id":"dossier_1743868800000_a1b2c3d4e5f6","status":"completed","compound":"Testosterone Cypionate","dossier_id":"abc-123","grade":"Recommend with monitoring","recommendation":"Suitable for clinical use under supervision","confidence":0.85,"pdf_url":"/api/v1/helix/dossier/abc-123/pdf"}}}}}}},"404":{"description":"Job or dossier not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"Job not found or expired"}}}}}}},"/helix/dossier/{dossierId}/pdf":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixDossierPdf","summary":"Download dossier PDF","description":"Download a rendered PDF of a completed evidence dossier.","tags":["Helix"],"parameters":[{"name":"dossierId","in":"path","required":true,"description":"The dossier ID (not the job ID).","schema":{"type":"string"}}],"responses":{"200":{"description":"PDF file.","headers":{"Content-Disposition":{"schema":{"type":"string"},"example":"attachment; filename=\"hormonaly-dossier-testosterone_cypionate.pdf\""}},"content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Dossier not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/helix/compare":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"post":{"operationId":"postHelixCompare","summary":"Head-to-head compound comparison","description":"Compare 2--3 compounds side-by-side on efficacy, safety, and evidence\nquality.\n\n**Tier requirement:** Advanced (`professional`) or Enterprise. Starter\nkeys receive `403 tier_insufficient`.\n\n**Organization policy:** applied after the safety gate, before any\ngeneration or billing. Every named compound must be permitted by your\npublished policy; otherwise the request is refused with HTTP 200,\n`blocked: true`, `block_reason: \"tenant_policy\"` and `data.policy`\n`{ version, reason, terms }`, not billed.\nThe `indication` is screened like a `/helix/query` question.\n","tags":["Helix"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixCompareRequest"},"example":{"compounds":["Testosterone Cypionate","Testosterone Enanthate"],"language":"en","indication":"Hypogonadism"}}}},"responses":{"200":{"description":"Comparison result.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixCompareResponse"},"example":{"success":true,"data":{"compounds":["Testosterone Cypionate","Testosterone Enanthate"],"indication":"Hypogonadism","protocols":[{"protocolTitle":"Testosterone Cypionate","category":"Hormones","evidenceLevel":"strong","evidenceGrade":"A","dosing":"200 mg/week","frequency":"Weekly","route":"IM","pros":["Long clinical track record"],"cons":["Peak-trough fluctuation"]},{"protocolTitle":"Testosterone Enanthate","category":"Hormones","evidenceLevel":"strong","evidenceGrade":"A","dosing":"200 mg/week","frequency":"Weekly","route":"IM","pros":["Widely available"],"cons":["Peak-trough fluctuation"]}],"recommendation":"Both esters are clinically equivalent for TRT.","comparison_notes":"Cypionate has a marginally longer half-life.","key_differences":[{"dimension":"Half-life","details":"Cypionate ~8 days vs Enanthate ~7 days"}],"best_for":[{"scenario":"US clinics","protocol":"Testosterone Cypionate","reason":"Preferred in the US due to familiarity"}]},"usage":{"tokens":2200,"latency_ms":6300}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/IdempotencyKeyReuseMismatch"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"Your organization's published policy could not be loaded, so the request was refused rather than processed without it. Retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"policy_unavailable","message":"Your organization's policy could not be loaded; the request was not processed. Retry shortly."}}}}}}},"/helix/protocols/{compound}":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixProtocols","summary":"Look up protocols for a compound","description":"Search the protocol database for entries matching the given compound\nname.  Returns evidence grades, FDA status, and summaries.\n","tags":["Helix"],"parameters":[{"name":"compound","in":"path","required":true,"description":"Compound name to search (case-insensitive, partial match).","schema":{"type":"string","maxLength":200}},{"name":"language","in":"query","required":false,"schema":{"type":"string","enum":["en","ar"],"default":"en"}}],"responses":{"200":{"description":"Matching protocols.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixProtocolsResponse"},"example":{"success":true,"data":{"compound":"metformin","protocol_count":2,"protocols":[{"id":"metformin-longevity","title":"Metformin Longevity Protocol","category":"longevity","evidence_level":"strong","grade":"A","fda_status":"FDA-approved (Type 2 Diabetes)","summary":"Metformin is a biguanide with extensive evidence...","indications":["type_2_diabetes","longevity"],"freshness":{"version":4,"content_hash":"a1f09c...","content_changed_at":"2026-09-20T08:00:00.000Z","last_scanned_at":"2026-09-26T02:00:00.000Z","last_verified_at":"2026-09-20T08:00:00.000Z","corpus_version":1289,"retracted_citations":0,"flagged_citations":0}}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No protocols found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"No protocols found for this compound","suggestion":"Try a different spelling or the generic name"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/helix/protocols/batch":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"post":{"operationId":"batchHelixProtocols","summary":"Batch-resolve protocols","description":"Resolve up to 100 protocols in one call by `slugs`, `ids`, and/or\n`names` (provide at least one non-empty array — they are merged and\nde-duplicated). Matches are exact (case-insensitive) on protocol id or\ntitle. Terms with no match are returned in `not_found` rather than\nfailing the request. Saves the per-item round-trip when hydrating a set\nof known compounds.\n","tags":["Helix"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slugs":{"type":"array","items":{"type":"string"},"description":"Protocol slugs/ids to resolve."},"ids":{"type":"array","items":{"type":"string"},"description":"Alias for slugs; merged with them."},"names":{"type":"array","items":{"type":"string"},"description":"Compound/protocol names to resolve."}}},"example":{"slugs":["metformin-longevity"],"names":["BPC-157","TB-500"]}}}},"responses":{"200":{"description":"Resolved protocols plus any unmatched terms.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"protocols":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string","nullable":true},"evidence_level":{"type":"string","nullable":true},"grade":{"type":"string","nullable":true,"enum":["A","B","C","D"]},"fda_status":{"type":"string","nullable":true},"freshness":{"$ref":"#/components/schemas/ProtocolFreshness"}}}},"not_found":{"type":"array","items":{"type":"string"},"description":"Requested terms that matched no protocol."},"found_count":{"type":"integer"},"requested_count":{"type":"integer"}}},"meta":{"type":"object"}}}}}},"400":{"description":"No terms provided, or batch larger than 100 entries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/helix/protocols/resolve":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"resolveHelixProtocol","summary":"Resolve a compound name to a protocol slug","description":"Given a compound `name`, return the canonical protocol `id` (slug) with\na confidence score plus up to four alternatives. Saves the search →\npick round-trip when you have a name and want the id for\n`GET /helix/protocols/{compound}`. Confidence: exact id 1.0, exact\ntitle 0.95, prefix 0.8, substring 0.5.\n","tags":["Helix"],"parameters":[{"name":"name","in":"query","required":true,"description":"Compound or protocol name to resolve (2–200 chars).","schema":{"type":"string","minLength":2,"maxLength":200}}],"responses":{"200":{"description":"Best match plus alternatives.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"best_match":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string","nullable":true},"confidence":{"type":"number","format":"float"}}},"alternatives":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string","nullable":true},"confidence":{"type":"number","format":"float"}}}}}},"meta":{"type":"object"}}},"example":{"success":true,"data":{"best_match":{"id":"bpc-157","title":"BPC-157","category":"peptides","confidence":1},"alternatives":[]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No protocol matches this name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/helix/usage":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixUsage","summary":"Partner usage analytics","description":"Returns a time-bucketed breakdown of your API consumption — request\ncounts, token usage, latency percentiles (p50/p90/p95/p99), per-endpoint\nusage, and HTTP status distribution. Use this to monitor billing,\ndiagnose error spikes, and capacity-plan without building your own log\npipeline.\n\nDefault window: last 30 days. Maximum window: 90 days. For older data,\npage by adjusting `from` and `to`.\n\n**Sandbox vs production.** Sandbox (`hk_test_`) traffic is metered against\na separate allowance and is reported separately here. By default this\nendpoint reports the pool matching the key you called it with, so these\ntotals reconcile with the `X-Token-Budget-*` headers on the same response.\nPass `mode` to inspect the other pool. The pool being reported is echoed\nback as `data.mode`.\n\n**No cost figures.** Responses carry request counts, token counts, latency\nand status distribution — never monetary amounts. Billing figures live on\nyour partner dashboard, which reports your invoice rather than our\nprovider spend.\n\n**Tier requirement:** see your partner allowlist; included in Professional and Enterprise.\n","tags":["Helix"],"parameters":[{"name":"from","in":"query","required":false,"description":"Start of window (ISO-8601 date or datetime). Default — 30 days ago.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"End of window (ISO-8601 date or datetime). Default — now.","schema":{"type":"string","format":"date-time"}},{"name":"mode","in":"query","required":false,"description":"Which key pool to report. Defaults to the mode of the key making the\nrequest (`live` for `hk_live_`, `test` for `hk_test_`), so the numbers\nmatch the budget headers on the same response. `all` combines both.\n","schema":{"type":"string","enum":["live","test","all"]}}],"responses":{"200":{"description":"Usage analytics for the requested window.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"mode":{"type":"string","enum":["live","test","all"],"description":"Which key pool these numbers describe. Defaults to the mode of the calling key."},"window":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"days":{"type":"integer"}}},"summary":{"type":"object","description":"Aggregate totals for the window (requests, tokens, errors)."},"daily":{"type":"array","description":"Per-day buckets.","items":{"type":"object"}},"by_endpoint":{"type":"array","description":"Per-endpoint breakdown.","items":{"type":"object"}},"latency_ms":{"type":"object","description":"Latency percentiles in milliseconds.","properties":{"p50":{"type":"integer"},"p90":{"type":"integer"},"p95":{"type":"integer"},"p99":{"type":"integer"}}},"by_status":{"type":"array","description":"HTTP status code distribution.","items":{"type":"object","properties":{"statusCode":{"type":"integer"},"count":{"type":"integer"}}}}}},"meta":{"type":"object"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Endpoint not on your tier's allowlist. Contact sales to upgrade.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/helix/status":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixStatus","summary":"Aggregated service status","description":"Rolls up the health of Helix and its sub-services (database, AI budget)\ninto a single `operational`/`degraded` verdict, so you can poll one\nendpoint instead of each `/health` route separately. Unlike the\nunauthenticated `/helix/health` liveness probe, this is a bearer-auth\npartner endpoint.\n","tags":["Helix"],"responses":{"200":{"description":"Aggregated status across sub-services.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"status":{"type":"string","enum":["operational","degraded"]},"services":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"status":{"type":"string","enum":["operational","degraded"]},"detail":{"type":"string"}}}},"timestamp":{"type":"string","format":"date-time"}}},"meta":{"type":"object"}}},"example":{"success":true,"data":{"status":"operational","services":[{"name":"helix","status":"operational"},{"name":"database","status":"operational"},{"name":"ai_budget","status":"operational"}],"timestamp":"2026-07-24T16:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"503":{"description":"Status aggregation failed. Besides this, the only 503 on the partner surface with a machine-readable `error` code is `policy_unavailable` (/helix/query, /helix/jobs, /helix/compare, /helix/dossier); the rate limiter's DB-failure 503 and the AI-budget 503 return a human-readable message only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"service_unavailable","message":"Status aggregation failed"}}}}}}},"/evidence/health":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getEvidenceHealth","summary":"Evidence health check","description":"Liveness, plus operational diagnostics for authenticated callers.\n\nSame two-shape contract as `/helix/health` and `/scribe/health`: without\na valid partner key you get `status`, `service`, `version` and\n`timestamp` only; present a valid `Authorization: Bearer` key and the\nresponse also carries `uptime_seconds` (this service publishes no\n`capabilities` array). Polling does not count against key usage.\n","tags":["Health"],"security":[],"responses":{"200":{"description":"Service is live. Diagnostic fields present only when a valid partner key was supplied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScribeHealthResponse"},"examples":{"unauthenticated":{"summary":"No key — liveness only","value":{"status":"ok","service":"evidence-api","version":"1.0.0","timestamp":"2026-04-05T12:00:00.000Z"}}}}}}}}},"/scribe/health":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getScribeHealth","summary":"Scribe health check","description":"Liveness, plus operational diagnostics for authenticated callers.\n\nSame two-shape contract as `/helix/health`: without a valid partner key\nyou get `status`, `service`, `version` and `timestamp` only; present a\nvalid `Authorization: Bearer` key and the response also carries uptime,\ncapabilities and the recommended client timeout. Always returns 200,\nwhatever the key's billing state.\n","tags":["Health"],"security":[],"responses":{"200":{"description":"Service is live. Diagnostic fields present only when a valid partner key was supplied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScribeHealthResponse"},"examples":{"unauthenticated":{"summary":"No key — liveness only","value":{"status":"ok","service":"scribe-api","version":"1.0.0","timestamp":"2026-04-05T12:00:00.000Z"}},"authenticated":{"summary":"Valid partner key — full diagnostics","value":{"status":"ok","service":"scribe-api","version":"1.0.0","timestamp":"2026-04-05T12:00:00.000Z","uptime_seconds":86400,"capabilities":["generate"],"recommended_timeout_ms":100000}}}}}}}}},"/scribe/generate":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"post":{"operationId":"postScribeGenerate","summary":"Generate clinical note","description":"Generate an AI-powered clinical note (SOAP, DAP, or narrative format)\nfrom one or more protocol selections with optional lab values and\nclinical context.\n\n**Tier requirement:** none — every API tier may call this endpoint;\ntiers govern volume only.\n\n**Recommended client timeout:** 100 seconds (`recommended_timeout_ms`\non `GET /scribe/health`).\n","tags":["Scribe"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScribeGenerateRequest"},"example":{"protocols":[{"name":"Testosterone Cypionate","dose":"200 mg","frequency":"weekly","route":"IM"},{"name":"Anastrozole","dose":"0.5 mg","frequency":"twice weekly","route":"oral"}],"clinical_context":"42M presenting for TRT follow-up. Reports improved energy and libido.","note_format":"soap","language":"en","lab_values":[{"name":"Total Testosterone","value":"850","unit":"ng/dL"},{"name":"Estradiol","value":"32","unit":"pg/mL"}]}}}},"responses":{"200":{"description":"Generated clinical note.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Idempotency-Replay":{"description":"`true` when this response was replayed from a prior request with the same Idempotency-Key and body (no new generation, no new charge). Note: Scribe uses `Idempotency-Replay`; Helix uses `Idempotency-Replayed`.","schema":{"type":"boolean"},"example":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScribeGenerateResponse"},"example":{"success":true,"data":{"format":"soap","content":"SUBJECTIVE:\nPatient is a 42-year-old male presenting for TRT follow-up...","sections":{"subjective":"Patient is a 42-year-old male...","objective":"Vital signs stable. Labs reviewed...","assessment":"Hypogonadism, well-controlled on current TRT regimen...","plan":"Continue Testosterone Cypionate 200 mg IM weekly..."},"protocols_summary":"Testosterone Cypionate 200 mg IM weekly, Anastrozole 0.5 mg PO twice weekly","monitoring_plan":"Repeat labs in 8 weeks: Total T, Free T, Estradiol, CBC, PSA","disclaimers":["AI-generated note -- must be reviewed by a licensed provider."],"confidence_score":0.88,"interaction_alerts":[]},"meta":{"latency_ms":4200,"protocol_count":2,"language":"en","note_format":"soap"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/IdempotencyKeyInFlight"},"422":{"$ref":"#/components/responses/IdempotencyKeyReuseMismatch"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"AI service temporarily overloaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"service_overloaded","message":"AI service is temporarily busy. Retry with exponential backoff."}}}}}}},"/evidence":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"listEvidence","summary":"List all curated evidence entries","description":"Returns the full Hormonaly evidence library — every published study,\nmeta-analysis, and clinical guideline indexed by the platform. Includes\ntitle, journal, year, GRADE-mapped strength, findings summary, and\nPubMed/DOI provenance.\n\nUse this for offline evidence catalogs or to power your own evidence\nUI. Cached server-side for 15 minutes; safe to call frequently.\n\n**Tier requirement:** Evidence access must be on your allowlist. Contact sales if you see `403 endpoint_not_allowed`.\n","tags":["Evidence"],"responses":{"200":{"description":"Evidence list.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"}},"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"journal":{"type":"string"},"year":{"type":"integer"},"findings":{"type":"string"},"strength":{"type":"string","enum":["strong","moderate","emerging","weak","preclinical","preliminary"]},"url":{"type":"string","format":"uri","nullable":true},"pmid":{"type":"string","nullable":true},"provenance":{"type":"object","nullable":true,"description":"Structured PubMed/DOI provenance record.","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Evidence endpoint not on your tier's allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/evidence/{id}":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getEvidenceById","summary":"Fetch a single evidence entry","description":"Returns one evidence item by its ID. 404 if not found.","tags":["Evidence"],"parameters":[{"name":"id","in":"path","required":true,"description":"Evidence ID (URL-encoded if it contains slashes).","schema":{"type":"string"}}],"responses":{"200":{"description":"The evidence item.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Evidence endpoint not on your tier's allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Evidence item not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/helix/jobs":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"post":{"operationId":"postHelixJob","summary":"Enqueue an async job","description":"Submit a long-running query or scribe request as an async job.\nReturns a `job_id` and `poll_url` immediately (< 200 ms).\nPoll `GET /helix/jobs/{jobId}` until `status` is `done` or `failed`.\nResults are automatically evicted after 24 hours.\n\nIf a webhook URL is configured on your partner account, a\n`job.completed` webhook (see the top-level `webhooks` section) is\nalso delivered when the job finishes, on success and on failure.\n","tags":["Jobs"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixJobRequest"},"examples":{"query":{"summary":"Defer a clinical query","value":{"type":"query","payload":{"question":"What is the evidence for BPC-157 in tendon repair?","language":"en","detail_level":"clinical"}}},"scribe":{"summary":"Defer a clinical note","value":{"type":"scribe","payload":{"protocols":[{"name":"Testosterone Cypionate","dose":"200 mg","frequency":"weekly","route":"IM"}],"note_format":"soap","language":"en"}}}}}}},"responses":{"202":{"description":"Job enqueued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelixJobCreatedResponse"},"example":{"success":true,"data":{"job_id":"job_1743868800000_a1b2c3","status":"pending","type":"query","estimated_ms":20000,"poll_url":"/api/v1/helix/jobs/job_1743868800000_a1b2c3"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/IdempotencyKeyReuseMismatch"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"Your organization's published policy could not be loaded, so the request was refused rather than answered without it. Retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"policy_unavailable","message":"Your organization's policy could not be loaded; the request was not answered. Retry shortly."}}}}}}},"/helix/jobs/{jobId}":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getHelixJob","summary":"Poll async job status","description":"Poll an in-progress job or retrieve a completed result.\nPoll on a 2–5 second interval. Stop when `status` is `done` or `failed`.\nCompleted results expire after 24 hours.\n","tags":["Jobs"],"parameters":[{"name":"jobId","in":"path","required":true,"description":"The job ID returned by `POST /helix/jobs`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Job status. Shape varies by `status` field.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/HelixJobPendingResponse"},{"$ref":"#/components/schemas/HelixJobDoneResponse"},{"$ref":"#/components/schemas/HelixJobFailedResponse"}]},"examples":{"pending":{"summary":"Job still processing","value":{"success":true,"data":{"job_id":"job_1743868800000_a1b2c3","type":"query","status":"pending","elapsed_ms":3200,"estimated_ms":20000}}},"done":{"summary":"Job completed","value":{"success":true,"data":{"job_id":"job_1743868800000_a1b2c3","type":"query","status":"done","result":{"answer":"BPC-157 has shown promising evidence...","agents_used":["compound_research"],"confidence":{"score":0.72,"level":"moderate","factors":["Grade B evidence","3 citations"]},"grade":"B","related_protocols":[{"id":"bpc-157","title":"BPC-157 Protocol","category":"peptides","evidence_level":"moderate","grade":"B"}],"usage":{"tokens":1850}},"elapsed_ms":18500,"completed_at":"2026-04-18T12:00:18.500Z"}}},"failed":{"summary":"Job failed","value":{"success":false,"data":{"job_id":"job_1743868800000_a1b2c3","type":"query","status":"failed","error":"job_processing_failed"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Job not found or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"job_not_found","message":"Job not found or expired"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/helix/policy":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getTenantPolicy","summary":"Get your organization's policy","description":"The published version (enforced on /query, query jobs and the MCP question-answering\ntools; not yet on /compare, /dossier or catalog lookups), the draft,\nand every version. Precedence is fixed: platform safety, then evidence\ngrading, then your policy. A policy can only restrict; no field\nloosens a platform rule. Published versions are immutable and are\narchived when superseded.\n","tags":["Helix"],"responses":{"200":{"description":"Policy state.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"published":{"$ref":"#/components/schemas/TenantPolicyVersion"},"draft":{"$ref":"#/components/schemas/TenantPolicyVersion"},"versions":{"type":"array","items":{"type":"object","properties":{"version":{"type":"integer"},"status":{"type":"string","enum":["draft","published","archived"]},"content_hash":{"type":"string"},"published_at":{"type":"string","format":"date-time","nullable":true},"archived_at":{"type":"string","format":"date-time","nullable":true}}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/helix/policy/draft":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"put":{"operationId":"saveTenantPolicyDraft","summary":"Create or replace the policy draft","tags":["Helix"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["policy"],"properties":{"policy":{"$ref":"#/components/schemas/TenantPolicy"},"notes":{"type":"string","maxLength":1000}}},"example":{"policy":{"compounds":{"deny":["BPC-157"]},"evidence":{"min_grade":"B"}},"notes":"Formulary committee 2026-09"}}}},"responses":{"200":{"description":"The saved draft.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TenantPolicyVersion"}}}}}},"400":{"description":"The policy is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"invalid_policy","message":"Policy does not match the schema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"operationId":"discardTenantPolicyDraft","summary":"Discard the policy draft","tags":["Helix"],"responses":{"200":{"description":"Discarded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"discarded":{"type":"boolean"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"There is no draft.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"not_found"}}}}}}},"/helix/policy/publish":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"post":{"operationId":"publishTenantPolicy","summary":"Publish the policy draft","description":"Enforced immediately: the policy version is part of every answer cache\nkey, so answers cached under a previous policy are never served. The\nprevious version is archived. Requires a live key. Each answer's\nprovenance record carries the policy version it ran under.\n","tags":["Helix"],"responses":{"200":{"description":"The published version.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TenantPolicyVersion"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Publishing requires a live key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"live_key_required"}}}},"409":{"description":"There is no draft to publish.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"no_draft"}}}}}}},"/helix/policy/evaluate":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"post":{"operationId":"evaluateTenantPolicy","summary":"Dry-run a policy against a question","description":"No generation and not billed. Shows whether the draft (default) or published policy would refuse the question, which protocols it keeps, and the prompt block it adds.","tags":["Helix"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["question"],"properties":{"question":{"type":"string","maxLength":10000},"target":{"type":"string","enum":["draft","published"],"default":"draft"}}},"example":{"question":"BPC-157 dosing for tendon repair?"}}}},"responses":{"200":{"description":"Evaluation.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"version":{"type":"integer"},"status":{"type":"string"},"blocked":{"type":"boolean"},"reason":{"type":"string","nullable":true,"enum":["compound_denied","compound_not_allowed",null]},"terms":{"type":"array","items":{"type":"string"}},"protocols_considered":{"type":"array","items":{"type":"string"}},"protocols_kept":{"type":"array","items":{"type":"string"}},"buffers_stream":{"type":"boolean"},"prompt_block":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No draft / published policy to evaluate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"not_found"}}}}}}},"/helix/webhooks/events":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getWebhookEvents","summary":"List opt-in webhook events","description":"Knowledge events your webhook URL receives in addition to\n`job.completed` and usage alerts. `protocol.updated` fires after each\nreviewed protocol version is published (metadata only: id, version,\ncontent hash, changed field names, links; fetch content through the\nAPI). Deliveries are signed like every Hormonaly webhook\n(`X-Hormonaly-Signature-V2`) and carry `X-Hormonaly-Event` and\n`X-Hormonaly-Event-Id` (`<protocol>@v<version>`, unique per delivery).\n","tags":["Helix"],"responses":{"200":{"description":"Current subscriptions.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"string","enum":["protocol.updated"]}},"available":{"type":"array","items":{"type":"string"}},"webhook_configured":{"type":"boolean"}}}}},"example":{"success":true,"data":{"events":["protocol.updated"],"available":["protocol.updated"],"webhook_configured":true}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"put":{"operationId":"setWebhookEvents","summary":"Set opt-in webhook events","tags":["Helix"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"type":"string","enum":["protocol.updated"]}}}},"example":{"events":["protocol.updated"]}}}},"responses":{"200":{"description":"Updated subscriptions.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"string"}},"available":{"type":"array","items":{"type":"string"}}}}}}}}},"400":{"description":"An unknown event was requested.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"invalid_events","message":"events must be an array drawn from: protocol.updated"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/helix/provenance/{traceId}":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getAnswerProvenance","tags":["Helix"],"summary":"Provenance of one of your answers","description":"Append-only record of what produced an answer, looked up by the `x-trace-id` returned with it: served model and fallback flag, sha256 of the system prompt and of the answer text (sha256 of `data.answer` as UTF-8 equals `answerHash`), retrieved PMIDs, the ledger version (number + sha256) of each protocol it drew on, the knowledge corpus version, and the organization policy version applied. Records are written for generated answers; an answer replayed from cache and a refused request have none. Scoped to your account.\n","security":[{"BearerAuth":[]}],"parameters":[{"name":"traceId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provenance record.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"traceId":{"type":"string"},"surface":{"type":"string","enum":["partner_query_json","partner_query_stream","web_chat"]},"servedModel":{"type":"string","nullable":true},"isFallback":{"type":"boolean","nullable":true},"cacheHit":{"type":"boolean"},"promptHash":{"type":"string","nullable":true},"answerHash":{"type":"string","nullable":true},"answerChars":{"type":"integer","nullable":true},"evidenceGrade":{"type":"string","nullable":true},"retrievedPmids":{"type":"array","items":{"type":"string"}},"protocolVersions":{"type":"array","items":{"type":"object","properties":{"protocolId":{"type":"string"},"versionNumber":{"type":"integer","nullable":true},"contentHash":{"type":"string","nullable":true}}}},"corpusVersion":{"type":"integer","nullable":true},"tenantPolicyVersion":{"type":"integer","nullable":true,"description":"Your published organization policy version applied to the answer; null when none."},"createdAt":{"type":"string","format":"date-time"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No provenance for this trace id under your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"not_found"}}}}}}},"/helix/protocols/{id}/versions":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"listProtocolVersions","tags":["Helix"],"summary":"Governed version ledger of a protocol","description":"Every content version of the protocol, newest first: version number, sha256 of the content snapshot, the window it was in effect, the source (review approval, creation, withdrawal), and the review that published it. Ledger rows are immutable.\n","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Version ledger."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Unknown or restricted protocol.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"not_found"}}}}}}},"/helix/protocols/{id}/as-of":{"servers":[{"url":"/api/v1","description":"Production (v1)"}],"get":{"operationId":"getProtocolAsOf","tags":["Helix"],"summary":"What a protocol said at a point in time","description":"The protocol's content snapshot in effect at `date` (default now), with its version number, sha256 and effective window, from the immutable ledger. Coverage starts when the ledger was enabled; earlier dates return 404 rather than a guess.\n","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"date","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Snapshot in effect at that time."},"400":{"description":"date is not ISO-8601.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"invalid_date"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Unknown or restricted protocol, or no version covers that date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"not_found"}}}}}}},"/protocols":{"servers":[{"url":"/api/v2","description":"Production (v2 — envelope-normalised catalog and tool endpoints)"}],"get":{"operationId":"getV2Protocols","summary":"List protocols (envelope)","description":"Returns all protocols wrapped in the standard\n`{ success, data, meta }` envelope.\n\nThis is the v2 equivalent of the legacy `GET /api/protocols` endpoint\nwhich returns a bare array.  Legacy consumers are unaffected.\n\n**Base URL for this endpoint: `/api/v2`**\n","tags":["Catalog"],"security":[],"parameters":[{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by category slug."},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Free-text search on title and description."}],"responses":{"200":{"description":"Protocol list.","headers":{"Cache-Control":{"schema":{"type":"string"},"example":"public, max-age=300, stale-while-revalidate=600"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V2ProtocolsResponse"},"example":{"success":true,"data":[{"id":"bpc-157","title":"BPC-157 Protocol","category":"peptides","evidenceLevel":"moderate"}],"meta":{"count":1}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/categories":{"servers":[{"url":"/api/v2","description":"Production (v2 — envelope-normalised catalog and tool endpoints)"}],"get":{"operationId":"getV2Categories","summary":"List categories (envelope)","description":"Returns all protocol categories wrapped in the standard\n`{ success, data, meta }` envelope.\n\nThis is the v2 equivalent of the legacy `GET /api/categories` endpoint\nwhich returns a bare array.\n\n**Base URL for this endpoint: `/api/v2`**\n","tags":["Catalog"],"security":[],"responses":{"200":{"description":"Category list.","headers":{"Cache-Control":{"schema":{"type":"string"},"example":"public, max-age=300, stale-while-revalidate=600"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V2CategoriesResponse"},"example":{"success":true,"data":[{"id":1,"name":"Peptides","slug":"peptides"}],"meta":{"count":1}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tools/interaction-checker":{"servers":[{"url":"/api/v2","description":"Production (v2 — envelope-normalised catalog and tool endpoints)"}],"post":{"operationId":"postV2InteractionChecker","summary":"Check medication–protocol interactions (envelope)","description":"Checks for clinically significant interactions between a list of\nmedications and protocol compounds using AI-powered analysis.\n\nReturns the full interaction result wrapped in the standard\n`{ success, data, meta }` envelope. The legacy endpoint at\n`/api/tools/interaction-checker` returns a bare object.\n\n**Base URL for this endpoint: `/api/v2`**\n\nRequires authentication (user session or partner API key).\n","tags":["Tools"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InteractionCheckerRequest"},"example":{"medications":["Warfarin","Aspirin"],"protocols":["BPC-157","TB-500"],"clientContext":"65M with atrial fibrillation on anticoagulation therapy"}}}},"responses":{"200":{"description":"Interaction analysis result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V2InteractionCheckerResponse"},"example":{"success":true,"data":{"interactions":[{"medication":"Warfarin","protocol":"BPC-157","severity":"moderate","description":"Potential enhancement of anticoagulant effect","recommendation":"Monitor INR closely"}],"overallRiskLevel":"moderate","safeProtocols":["TB-500"],"cautionProtocols":["BPC-157"],"avoidProtocols":[],"summary":"BPC-157 requires close monitoring with Warfarin","monitoringRecommendations":["Monitor INR weekly for 4 weeks"]},"meta":{"checkedAt":"2026-04-18T12:00:00.000Z","compoundCount":4,"latency_ms":3200}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"webhooks":{"jobCompleted":{"post":{"operationId":"webhookJobCompleted","summary":"job.completed — async job finished","description":"Delivered to your configured webhook URL when an async job submitted\nvia `POST /helix/jobs` finishes (both `done` and `failed` outcomes).\n\nHeaders on every delivery:\n\n| Header | Description |\n|--------|-------------|\n| `X-Hormonaly-Signature` | `sha256=<hex>` — HMAC-SHA256 of the raw request body, keyed by your webhook secret. Omitted if no secret is configured. Verify with a constant-time compare before trusting the body. |\n| `X-Hormonaly-Job-Id` | The job id — use for idempotent dedup across retries. |\n| `User-Agent` | `Hormonaly-Webhook/1.0` |\n\nRetry policy: up to 4 attempts with exponential backoff (1 s, 8 s,\n64 s) on non-2xx responses, network errors, or a 10 s delivery\ntimeout. Redirect (3xx) responses are never followed and terminate\ndelivery — configure the final URL directly. Webhook URLs must be\nHTTPS and publicly routable (no localhost or private ranges).\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["event","job_id","type","status","result","error","completed_at"],"properties":{"event":{"type":"string","const":"job.completed"},"job_id":{"type":"string"},"type":{"type":"string","enum":["query","scribe"]},"status":{"type":"string","enum":["done","failed"]},"result":{"description":"The same result object returned by `GET /helix/jobs/{jobId}` for this job type. `null` when `status` is `failed`.\n","oneOf":[{"type":"object"},{"type":"null"}]},"error":{"description":"Human-readable failure message, or `null` on success.","oneOf":[{"type":"string"},{"type":"null"}]},"completed_at":{"type":"string","format":"date-time"}}},"examples":{"done":{"summary":"Successful query job","value":{"event":"job.completed","job_id":"job_1743868800000_a1b2c3","type":"query","status":"done","result":{"answer":"BPC-157 has shown promising evidence...","grade":"B"},"error":null,"completed_at":"2026-04-18T12:00:18.500Z"}},"failed":{"summary":"Failed job","value":{"event":"job.completed","job_id":"job_1743868800000_a1b2c3","type":"query","status":"failed","result":null,"error":"Model timed out","completed_at":"2026-04-18T12:01:30.000Z"}}}}}},"responses":{"200":{"description":"Return any 2xx quickly to acknowledge receipt; non-2xx responses trigger the retry policy.\n"}}}},"usageThresholdReached":{"post":{"operationId":"webhookUsageThresholdReached","summary":"usage.threshold_reached — 80% / 100% of included tokens, or the enforced cap","description":"Delivered to your configured webhook URL, at most once per calendar\nmonth per `alert`/`threshold_pct`, when production usage passes 80%\nor 100% of the tokens included in your plan (`alert: threshold`) or\nreaches the enforced monthly cap (`alert: hard_cap`, after which live\nkeys receive `429 monthly_budget_exceeded` until the 1st). Signed\nwith the same `X-Hormonaly-Signature-V2` / `X-Hormonaly-Timestamp` /\n`X-Hormonaly-Signature` headers as `job.completed`, plus\n`X-Hormonaly-Event: usage.threshold_reached` and\n`X-Hormonaly-Alert-Id` (stable per alert; use it for dedup). A copy\ngoes by email to the contact and billing addresses on your account.\nSingle attempt, no retry: the email is the fallback channel and the\nnumbers are always available from `GET /helix/usage` and the\n`X-Token-Budget-*` headers.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["event","alert","threshold_pct","tokens_used","tokens_included","cap_tokens","period","plan","occurred_at"],"properties":{"event":{"type":"string","const":"usage.threshold_reached"},"alert":{"type":"string","enum":["threshold","hard_cap"]},"threshold_pct":{"description":"Percent of included tokens for `threshold` alerts; `null` for `hard_cap`.","oneOf":[{"type":"integer"},{"type":"null"}]},"tokens_used":{"type":"integer"},"tokens_included":{"type":"integer"},"cap_tokens":{"description":"The enforced monthly cap, or `null` when none applies.","oneOf":[{"type":"integer"},{"type":"null"}]},"period":{"type":"string","description":"Calendar month, `YYYY-MM`."},"plan":{"type":"string"},"occurred_at":{"type":"string","format":"date-time"}}},"examples":{"eighty":{"summary":"80% of included tokens","value":{"event":"usage.threshold_reached","alert":"threshold","threshold_pct":80,"tokens_used":4000000,"tokens_included":5000000,"cap_tokens":10000000,"period":"2026-09","plan":"API Starter","occurred_at":"2026-09-12T15:30:00.000Z"}},"cap":{"summary":"Enforced cap reached","value":{"event":"usage.threshold_reached","alert":"hard_cap","threshold_pct":null,"tokens_used":10000000,"tokens_included":5000000,"cap_tokens":10000000,"period":"2026-09","plan":"API Starter","occurred_at":"2026-09-27T09:12:00.000Z"}}}}}},"responses":{"200":{"description":"Return any 2xx to acknowledge receipt."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"hk_live_... | hk_test_...","description":"Pass your partner API key as a Bearer token.\n```\nAuthorization: Bearer hk_live_abc123...\n```\n\n**Production vs sandbox.** `hk_live_` keys draw on your contracted\nmonthly token budget and appear on your invoice. `hk_test_` keys are\nsandbox credentials: same endpoints, same responses, but metered against\na separate monthly sandbox allowance that never reaches billing, COGS or\nyour production budget. Exhausting the sandbox allowance returns 429\n`sandbox_budget_exceeded` and does not affect production traffic;\nconversely, exhausting your production budget does not disable your\nsandbox key.\n\nEvery sandbox response carries `X-Helix-Key-Mode: test`. Check it in any\nenvironment where mixing the two would matter — it is the only thing\ndistinguishing sandbox output from production output.\n\n`X-Token-Budget-Limit` / `-Used` / `-Remaining` describe whichever pool\nthe presented key draws on, so the same client code reads remaining\nquota correctly on either credential.\n"}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-generated key. A retry with the same key AND the same request body returns the original buffered response instead of re-running the request or re-billing; POST /helix/jobs returns the original job_id. Replays carry `Idempotency-Replayed: true`.\n\nReusing one key with a different body is an error, not a replay — it returns 422 `idempotency_key_reuse_mismatch` rather than answering the earlier request. Streaming requests ignore the header entirely. Stored results are retained for 24 hours.\n\nAccepted shape differs by endpoint, so a single retry wrapper should use the stricter one: the Helix endpoints accept any string up to 255 chars and ignore a malformed header, while /scribe/generate requires 6–64 chars of `[A-Za-z0-9_-]` and rejects anything else with 400 `invalid_idempotency_key`. A UUID satisfies both.\n","schema":{"type":"string","maxLength":255}}},"headers":{"X-RateLimit-Limit":{"description":"Maximum requests per minute for your partner account.","schema":{"type":"integer"},"example":60},"X-RateLimit-Remaining":{"description":"Requests remaining in the current 60-second window.","schema":{"type":"integer"},"example":57},"X-RateLimit-Reset":{"description":"ISO-8601 timestamp when the current rate-limit window resets.","schema":{"type":"string","format":"date-time"},"example":"2026-04-05T12:01:00.000Z"},"Retry-After":{"description":"Seconds to wait before retrying (present only on 429 responses).","schema":{"type":"integer"},"example":12},"X-Token-Budget-Limit":{"description":"Your enforced monthly token cap: the tighter of the cap configured on your account and your plan's hard cap. Present only when a cap applies (Enterprise accounts without a configured cap have none).","schema":{"type":"integer"},"example":5000000},"X-Token-Budget-Used":{"description":"Tokens used this month to date.","schema":{"type":"integer"},"example":1200000},"X-Token-Budget-Remaining":{"description":"Tokens remaining this month. Self-throttle before this hits 0 to avoid a 429 monthly_budget_exceeded.","schema":{"type":"integer"},"example":3800000},"Idempotency-Replayed":{"description":"`true` when this buffered response was replayed from a prior request with the same Idempotency-Key (no new LLM call, no new charge).","schema":{"type":"boolean"},"example":true},"X-Helix-Response-Time":{"description":"Total server-side latency for the request.","schema":{"type":"string"},"example":"8230ms"},"X-Helix-Cache":{"description":"Whether the response was served from cache.","schema":{"type":"string","enum":["HIT","MISS"]},"example":"MISS"}},"responses":{"BadRequest":{"description":"Invalid or missing request parameters, OR a prompt-injection rejection.\n\nTwo shapes behind one status, and `error` does not mean the same thing in both — read this before branching on it.\n\nORDINARY VALIDATION failures return `{success: false, error: <human sentence>}` with no `message` field: `error` carries prose such as \"question is required and must be a string\", not a code. That is long-standing behaviour on these handlers.\n\nPROMPT-INJECTION rejections return `{success: false, error: \"prompt_injection\", message: <human sentence>}` — a machine-readable code in `error`, matching the convention the 401/402/403/429 responses use, with the prose moved to `message`. The guard runs ahead of authentication and inspects every string in the body, nested ones included, such as `payload.question` on POST /helix/jobs.\n\nTo tell them apart: injection rejections are the only 400 that carry a `message` field, and the only one whose `error` is a snake_case code. A deprecated `errorCode: \"PROMPT_INJECTION\"` is also emitted, duplicating `error`, for clients written against the guard's first release.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ErrorResponse"},{"type":"object","required":["success","error","message"],"properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string","enum":["prompt_injection"]},"message":{"type":"string"},"errorCode":{"type":"string","enum":["PROMPT_INJECTION"],"deprecated":true,"description":"Duplicates `error`. Retained for clients written against the first release."}}}]},"examples":{"validation":{"summary":"Ordinary request validation failure","value":{"success":false,"error":"question is required and must be a string"}},"promptInjection":{"summary":"Rejected by the prompt-injection guard","value":{"success":false,"error":"prompt_injection","message":"This request contains content that can't be processed as written. Remove instruction-like or role-changing text from the free-text fields and retry.","errorCode":"PROMPT_INJECTION"}}}}}},"IdempotencyKeyInFlight":{"description":"A request with this Idempotency-Key is still executing. The key is claimed before the handler runs, so a concurrent retry cannot start a second generation — which would bill you twice for one logical request. Retry after a few seconds (see Retry-After) with the SAME body; once the first request finishes, the retry returns its response as a normal replay.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"idempotency_key_in_flight","message":"A request with this Idempotency-Key is still being processed. Retry after a few seconds; do not change the body."}}}},"IdempotencyKeyReuseMismatch":{"description":"The supplied Idempotency-Key was already used with a DIFFERENT request body. Nothing is executed and nothing is replayed — replaying here would return the earlier request's answer. Send a fresh key, or resend the original body to get the original response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":"idempotency_key_reuse_mismatch","message":"Idempotency-Key was previously used with a different request body. Use a fresh key or resend the original body."}}}},"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"missing":{"summary":"No Authorization header","value":{"error":"authentication_required","message":"Missing or invalid Authorization header. Use: Bearer hk_live_..."}},"invalid":{"summary":"Invalid key","value":{"error":"invalid_api_key","message":"Invalid API key"}}}}}},"PaymentRequired":{"description":"Subscription payment required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"subscription_unpaid","message":"Your Helix API subscription requires payment. Please update your billing information."}}}},"Forbidden":{"description":"Endpoint not allowed for your tier, or subscription canceled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"tier":{"summary":"Tier insufficient","value":{"success":false,"error":"tier_insufficient","message":"Dossier generation requires Advanced or Enterprise tier. Contact sales to upgrade."}},"canceled":{"summary":"Subscription canceled","value":{"error":"subscription_canceled","message":"Your Helix API subscription has been canceled. Please contact sales to reactivate."}},"endpoint":{"summary":"Endpoint not in allowed list","value":{"error":"endpoint_not_allowed","message":"Your API tier does not include access to /api/v1/helix/compare. Contact sales to upgrade."}}}}}},"RateLimited":{"description":"Rate limit or token budget exceeded. `error` distinguishes them: `rate_limit_exceeded` (per-minute), `monthly_budget_exceeded` (production token budget), or `sandbox_budget_exceeded` (sandbox allowance on an hk_test_ key).","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"rate_limit":{"summary":"Per-minute rate limit exceeded","value":{"error":"rate_limit_exceeded","message":"Rate limit exceeded. Maximum 60 requests per minute. Retry after 12 seconds.","retryAfter":12}},"budget":{"summary":"Monthly token budget exceeded","value":{"error":"monthly_budget_exceeded","message":"Monthly token budget exceeded. Resets on the 1st of the next month. Contact sales to increase your limit.","budget":5000000,"used":5000001}}}}}}},"schemas":{"HelixCitation":{"type":"object","description":"One numbered source. `id` matches the answer's [N] marker.","properties":{"id":{"type":"integer","description":"The number of this source's [N] marker in the answer (sources not cited get ids above the cited range)."},"pmid":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"citation_type":{"type":"string","enum":["pmid","narrative"]},"source_id":{"type":"string","nullable":true,"description":"For a reviewed internal entry (no PMID), its id (HKB-NNNN); a claim's source_ids resolve to it."},"title":{"type":"string","nullable":true},"authors":{"type":"array","items":{"type":"string"}},"year":{"type":"integer","nullable":true,"description":"Publication year (null when PubMed has none)."},"journal":{"type":"string","nullable":true},"evidence_level":{"type":"string","nullable":true,"enum":["guideline","systematic_review","rct","clinical_trial","observational","case_report","narrative_review","preclinical","other",null],"description":"Study type, from the PubMed publication type, else the curated study design, else the title."},"publication_types":{"type":"array","items":{"type":"string"},"description":"PubMed PublicationType list, when the PubMed record was fetched."},"verification":{"type":"string","enum":["verified","unverified","invalid","retracted","mismatched","pending"]},"passages":{"type":"array","description":"Paragraphs from the paper's open-access full text (Europe PMC) that match the question, verbatim, with the section they come from. Empty when the paper is not open access or no paragraph matched.\n","items":{"$ref":"#/components/schemas/HelixFullTextPassage"}}}},"HelixFullTextPassage":{"type":"object","description":"A verbatim paragraph from an open-access paper's full text.","properties":{"pmcid":{"type":"string","description":"PubMed Central id of the full text (PMC1234567)."},"section":{"type":"string","enum":["recommendations","results","conclusions","discussion","methods","introduction","other"],"description":"The role of the section the paragraph sits in."},"section_title":{"type":"string","nullable":true,"description":"The heading the paragraph sits under, as printed."},"text":{"type":"string"},"url":{"type":"string","description":"The article on PubMed Central."}}},"HelixEvidenceStamp":{"type":"object","description":"How strong and how current the evidence behind this answer is. Absent on a safety-redacted answer.","properties":{"as_of":{"type":"string","format":"date","nullable":true,"description":"Date through which the evidence was checked, the latest of the live PubMed search behind this answer, the last corpus change and the last evidence-loop run."},"corpus_version":{"type":"integer","nullable":true},"corpus_updated_at":{"type":"string","format":"date-time","nullable":true},"evidence_checked_at":{"type":"string","format":"date-time","nullable":true,"description":"When the continuous evidence loop (protocol scan, retraction sweep) last checked the corpus."},"live_literature_search":{"type":"boolean","description":"True when live PubMed (including the last 24 months) was searched for the evidence behind this answer."},"live_literature_searched_at":{"type":"string","format":"date-time","nullable":true,"description":"When that search ran; earlier than the answer when retrieval was served from cache."},"newest_source_year":{"type":"integer","nullable":true},"strength":{"type":"string","nullable":true,"enum":["strong","moderate","limited","insufficient",null]},"summary":{"type":"string","nullable":true},"levels":{"type":"object","description":"Count of numbered sources per evidence level.","additionalProperties":{"type":"integer"}}}},"HelixCitationCheck":{"type":"object","description":"Result of the claim-by-claim check that each cited sentence is supported by its source. Absent when the check did not run.","properties":{"checked":{"type":"integer","description":"Cited sentences judged."},"supported":{"type":"integer","description":"Cited sentences with at least one source found supporting them. Never more than `checked`. (Before 2026-11 this counted supported sentence-source pairs; that count is now `pairs_supported`.)"},"pairs_checked":{"type":"integer","description":"(sentence, source) pairs judged. A sentence citing three sources is three pairs."},"pairs_supported":{"type":"integer","description":"(sentence, source) pairs found supported."},"reanchored":{"type":"integer"},"dropped":{"type":"integer"},"removed_sentences":{"type":"integer"},"unclear":{"type":"integer"},"overstated":{"type":"integer","description":"Cited sentences whose source is the right one but whose wording states causation or benefit the study design cannot show. Their citations are kept."},"mismatch_types":{"type":"object","description":"Unsupported (sentence, source) pairs by kind: compound, condition, population, design, outcome, direction, magnitude, timepoint, causal_language, other. Omitted kinds are zero.","additionalProperties":{"type":"integer"}}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","description":"Machine-readable error code.","example":"invalid_api_key"},"message":{"type":"string","description":"Human-readable description.","example":"Invalid API key"},"retryAfter":{"type":"integer","description":"Seconds to wait (rate-limit errors)."},"budget":{"type":"integer","nullable":true,"description":"Monthly token budget (budget errors)."},"used":{"type":"integer","nullable":true,"description":"Tokens used this month (budget errors)."},"suggestion":{"type":"string","nullable":true},"retry_with":{"type":"object","additionalProperties":true,"description":"Suggested parameters for retry (timeout errors)."}}},"HelixHealthResponse":{"type":"object","description":"Two shapes. Without a valid partner key only the four liveness fields (status, service, version, timestamp) are returned; the diagnostic fields below are present only when the request carries a valid `Authorization: Bearer` key. Health never returns a non-200, including for an expired or over-budget key, so it cannot be used to probe key validity.","required":["status","service","version","timestamp"],"properties":{"status":{"type":"string","enum":["ok"]},"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"service":{"type":"string"},"uptime_seconds":{"type":"integer","description":"Authenticated callers only."},"capabilities":{"type":"array","description":"Authenticated callers only.","items":{"type":"string"}},"recommended_timeout_ms":{"type":"integer","description":"Authenticated callers only. What to set a NON-streaming client timeout to. Derived from the deadline that actually cancels the request plus a margin, so it is always longer than the server's own ceiling — a client that aborts earlier races our structured 504 and sees a connection reset instead."},"recommended_stream_timeout_ms":{"type":"integer","description":"Authenticated callers only. The same guidance for the SSE streaming path, whose ceiling is much higher than the buffered one."},"timeouts_ms":{"type":"object","description":"Authenticated callers only. The server-side deadlines these recommendations are derived from.","properties":{"query_hard":{"type":"integer","description":"Whole-request ceiling for non-streaming POST /helix/query."},"stream_hard":{"type":"integer","description":"Absolute ceiling for a streamed request."},"stream_stall":{"type":"integer","description":"Max gap between SSE content chunks before the stream is declared dead."}}},"models":{"type":"object","description":"Authenticated callers only. Model ids currently serving each detail_level, read from the live router. Values change when models are swapped; do not pin to them.","properties":{"clinical":{"type":"string","description":"Model serving detail_level=clinical.","examples":["gemini-2.5-pro"]},"summary":{"type":"string","description":"Model serving detail_level=summary.","examples":["gemini-2.5-flash"]}}}}},"HelixQueryRequest":{"type":"object","required":["question"],"properties":{"question":{"type":"string","maxLength":10000,"description":"The clinical question to answer."},"language":{"type":"string","enum":["en","ar"],"default":"en"},"detail_level":{"type":"string","enum":["clinical","summary"],"default":"clinical","description":"`summary` uses a faster model and shorter output."},"include_citations":{"type":"boolean","default":true},"include_three_lens":{"type":"boolean","default":false,"description":"Include longevity/health/performance scoring."},"bypass_cache":{"type":"boolean","default":false,"description":"Force a fresh AI generation, ignoring cache."},"enrich_citations":{"type":"boolean","default":false,"description":"Enrich returned citations with title/authors/year/journal fetched from PubMed (adds latency). Ignored unless `include_citations` is true.\n"},"partner_formulary":{"type":"array","items":{"type":"string"},"maxItems":500,"description":"Your available-compound catalogue. When provided, Helix prefers on-formulary compounds and flags off-formulary recommendations. Each entry is capped at 200 characters; the list is capped at 500 entries.\n"},"on_formulary_only":{"type":"boolean","default":false,"description":"Strict mode. When true (and `partner_formulary` is set), Helix only recommends compounds in the formulary, noting the closest on-formulary alternative when the best-evidence answer is off-formulary.\n"},"stream":{"type":"boolean","default":false,"description":"Request a Server-Sent Events stream instead of a buffered JSON response. Equivalent to sending `Accept: text/event-stream`. See the \"Streaming (SSE)\" description on this operation for the event catalog.\n"},"verbosity":{"type":"string","enum":["standard","concise"],"default":"concise","description":"Defaults to `concise` — a focused 200-350 word answer optimized for programmatic consumption, and materially lower latency. Set `standard` for the long-form analysis (answer-first, typically 400-650 words).\n"},"patient_context":{"type":"object","description":"Optional patient profile. When provided, Helix tailors dosing, monitoring, and safety to it and reasons over the listed conditions and current medications for interactions/contraindications. Every field is length/count-capped; a non-object is rejected with 400. For async jobs it is stored with the job and evicted after 24 hours.\n","properties":{"age":{"type":"integer"},"sex":{"type":"string","enum":["male","female"]},"weight_kg":{"type":"number"},"conditions":{"type":"array","items":{"type":"string"}},"medications":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dose":{"type":"string"}}}},"labs":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"},"unit":{"type":"string"},"ref_range":{"type":"string"}}}},"allergies":{"type":"array","items":{"type":"string"}},"goals":{"type":"array","items":{"type":"string"}}}},"history":{"type":"array","maxItems":20,"description":"Optional prior turns of the conversation, oldest first, for follow-up questions (\"what about in CKD?\"). The API is stateless: send the turns you want considered on each request. The last two user turns plus `question` drive retrieval, routing and safety screening; the turns reach the model as fenced context data, never as instructions. Each `content` is capped at 8,000 characters and the whole history at 32,000; a malformed history is rejected with 400. Requests with history bypass the semantic cache and are cached per exact history.\n","items":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string","maxLength":8000}}}}}},"HelixQueryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"blocked":{"type":"boolean","description":"Present and true when the question was refused before generation (HTTP 200, not billed). See block_reason.\n"},"block_reason":{"type":"string","enum":["safety","guardrail","guardrail_unavailable","tenant_policy"],"description":"Why the question was refused. `safety` is the platform safety gate and always takes precedence; `tenant_policy` is your organization's published policy (details in data.policy).\n"},"data":{"type":"object","properties":{"policy":{"type":"object","description":"Present when your organization has a published policy. On an answered question: `{ version, applied }`, where `applied` lists what the policy did (passages removed, grade-floor label, disclaimer). On a tenant_policy refusal: `{ version, reason, terms }`.\n","properties":{"version":{"type":"integer"},"applied":{"type":"array","items":{"type":"string"}},"reason":{"type":"string","enum":["compound_denied","compound_not_allowed"]},"terms":{"type":"array","items":{"type":"string"}}}},"answer":{"type":"string","description":"The AI-generated evidence-based answer."},"bottom_line":{"type":"string","nullable":true,"description":"The answer's opening paragraph as plain text (markdown and citation markers removed): the direct answer to show first. Null when the answer has no prose paragraph or was withheld.\n"},"claims":{"type":"array","description":"Each sentence of the answer that carries inline citation markers, with the marker numbers and the PMIDs they resolve to in the answer's References section. Derived deterministically from the final, citation-gated text. A marker whose reference has no PMID is listed with an empty `pmids`; when that reference is a reviewed internal entry (HKB-NNNN), its id is in `source_ids`. Empty when the answer was withheld.\n","items":{"type":"object","properties":{"text":{"type":"string"},"citation_numbers":{"type":"array","items":{"type":"integer"}},"pmids":{"type":"array","items":{"type":"string"}},"source_ids":{"type":"array","items":{"type":"string"}},"passages":{"type":"array","description":"Full-text paragraphs (open-access papers only) that this sentence restates, at most one per cited paper. Absent when none matches.\n","items":{"type":"object","properties":{"pmid":{"type":"string"},"pmcid":{"type":"string"},"section":{"type":"string"},"text":{"type":"string"},"url":{"type":"string"}}}}}}},"agents_used":{"type":"array","items":{"type":"string"},"description":"Internal agent intents that contributed to the answer."},"agent_attributions":{"type":"array","items":{"type":"object","properties":{"agent":{"type":"string"},"contribution":{"type":"string"}}}},"confidence":{"type":"object","properties":{"score":{"type":"number","minimum":0,"maximum":1,"description":"Confidence score (0-1)."},"level":{"type":"string","enum":["high","moderate","low","very_low"]},"factors":{"type":"array","items":{"type":"string"}}}},"grade":{"type":"string","nullable":true,"enum":["A","B","C","D",null],"description":"Evidence grade from the protocol database. Null when `evidence.strength` is `insufficient` (no retrieved source could be confirmed as addressing the question); `confidence` is then capped at low and says why in its factors. The grade and confidence never contradict `evidence`."},"recommendation":{"type":"string","nullable":true},"related_protocols":{"type":"array","items":{"$ref":"#/components/schemas/ProtocolSummary"}},"citations":{"type":"array","description":"Present when `include_citations` is true. Only papers that passed the retraction and relevance gates are listed.","items":{"$ref":"#/components/schemas/HelixCitation"}},"evidence":{"$ref":"#/components/schemas/HelixEvidenceStamp"},"citation_check":{"$ref":"#/components/schemas/HelixCitationCheck"},"three_lens":{"type":"object","nullable":true,"description":"Present when `include_three_lens` is true.","properties":{"longevity":{"$ref":"#/components/schemas/LensScore"},"health_and_disease":{"$ref":"#/components/schemas/LensScore"},"performance":{"$ref":"#/components/schemas/LensScore"},"overall_recommendation":{"type":"string","nullable":true}}},"orchestration_steps":{"type":"array","description":"Pipeline execution trace (when available).","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["done","skipped"]},"durationMs":{"type":"integer"},"agentName":{"type":"string"}}}}}},"usage":{"$ref":"#/components/schemas/UsageInfo"}}},"LensScore":{"type":"object","nullable":true,"properties":{"efficacy":{"type":"number","nullable":true},"safety":{"type":"number","nullable":true}}},"ProtocolSummary":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string"},"evidence_level":{"type":"string","nullable":true},"grade":{"type":"string","nullable":true,"enum":["A","B","C","D",null]}}},"UsageInfo":{"type":"object","properties":{"tokens":{"type":"integer","description":"Total tokens consumed."},"latency_ms":{"type":"integer","description":"Server-side latency in milliseconds."},"quality_retries":{"type":"integer","description":"Number of self-correction retries (query only)."}}},"HelixDossierRequest":{"type":"object","required":["compound"],"properties":{"compound":{"type":"string","maxLength":500,"description":"Name of the compound to generate a dossier for."},"language":{"type":"string","enum":["en","ar"],"default":"en"}}},"HelixDossierJobCreatedResponse":{"type":"object","properties":{"success":{"type":"boolean"},"blocked":{"type":"boolean","description":"Present and true when the request was refused before generation (HTTP 200, not billed). See block_reason.\n"},"block_reason":{"type":"string","enum":["safety","guardrail","guardrail_unavailable","tenant_policy"]},"data":{"type":"object","properties":{"answer":{"type":"string","description":"Refusal text; present only when blocked."},"policy":{"type":"object","description":"Present when your organization has a published policy. On a result: `{ version, disclaimer? }`. On a tenant_policy refusal: `{ version, reason, terms }`.\n","properties":{"version":{"type":"integer"},"disclaimer":{"type":"string"},"reason":{"type":"string","enum":["compound_denied","compound_not_allowed"]},"terms":{"type":"array","items":{"type":"string"}}}},"job_id":{"type":"string"},"status":{"type":"string","enum":["processing"]},"compound":{"type":"string"},"estimated_seconds":{"type":"integer"},"poll_url":{"type":"string"}}}}},"DossierJobProcessingResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string","enum":["processing"]},"compound":{"type":"string"},"elapsed_seconds":{"type":"integer"},"estimated_remaining":{"type":"integer"}}}}},"DossierJobCompletedResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string","enum":["completed"]},"compound":{"type":"string"},"dossier_id":{"type":"string"},"grade":{"type":"string","nullable":true},"recommendation":{"type":"string","nullable":true},"confidence":{"type":"number"},"three_lens":{"type":"object","nullable":true},"paper_count":{"type":"integer"},"pdf_url":{"type":"string","nullable":true},"policy":{"type":"object","description":"Present when your organization has a published policy. On a result: `{ version, disclaimer? }`. On a tenant_policy refusal: `{ version, reason, terms }`.\n","properties":{"version":{"type":"integer"},"disclaimer":{"type":"string"},"reason":{"type":"string","enum":["compound_denied","compound_not_allowed"]},"terms":{"type":"array","items":{"type":"string"}}}}}}}},"DossierJobFailedResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string","enum":["failed"]},"compound":{"type":"string"},"error":{"type":"string"}}}}},"HelixCompareRequest":{"type":"object","required":["compounds"],"properties":{"compounds":{"type":"array","items":{"type":"string","maxLength":200},"minItems":2,"maxItems":3,"description":"Names of compounds to compare."},"language":{"type":"string","enum":["en","ar"],"default":"en"},"indication":{"type":"string","maxLength":500,"default":"General comparison","description":"Clinical indication to compare against."}}},"HelixCompareResponse":{"type":"object","properties":{"success":{"type":"boolean"},"blocked":{"type":"boolean","description":"Present and true when the request was refused before generation (HTTP 200, not billed). See block_reason.\n"},"block_reason":{"type":"string","enum":["safety","guardrail","guardrail_unavailable","tenant_policy"]},"data":{"type":"object","properties":{"answer":{"type":"string","description":"Refusal text; present only when blocked."},"policy":{"type":"object","description":"Present when your organization has a published policy. On a result: `{ version, disclaimer? }`. On a tenant_policy refusal: `{ version, reason, terms }`.\n","properties":{"version":{"type":"integer"},"disclaimer":{"type":"string"},"reason":{"type":"string","enum":["compound_denied","compound_not_allowed"]},"terms":{"type":"array","items":{"type":"string"}}}},"compounds":{"type":"array","items":{"type":"string"}},"indication":{"type":"string"},"protocols":{"type":"array","items":{"type":"object","additionalProperties":true}},"recommendation":{"type":"string","nullable":true},"comparison_notes":{"type":"string","nullable":true},"key_differences":{"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string"},"details":{"type":"string"}}}},"best_for":{"type":"array","items":{"type":"object","properties":{"scenario":{"type":"string"},"protocol":{"type":"string"},"reason":{"type":"string"}}}}}},"usage":{"$ref":"#/components/schemas/UsageInfo"}}},"TenantPolicy":{"type":"object","additionalProperties":false,"description":"A private organization policy. Restrict-only: there is no field that\nloosens platform safety or evidence grading.\n","properties":{"compounds":{"type":"object","additionalProperties":false,"properties":{"deny":{"type":"array","maxItems":500,"items":{"type":"string","minLength":2,"maxLength":120}},"allow_only":{"type":"array","maxItems":500,"items":{"type":"string","minLength":2,"maxLength":120}}}},"evidence":{"type":"object","additionalProperties":false,"properties":{"min_grade":{"type":"string","enum":["A","B","C","D"]}}},"formulary":{"type":"object","additionalProperties":false,"properties":{"entries":{"type":"array","maxItems":500,"items":{"type":"string","maxLength":200}},"on_formulary_only":{"type":"boolean"}}},"instructions":{"type":"string","maxLength":2000},"output":{"type":"object","additionalProperties":false,"properties":{"disclaimer":{"type":"string","maxLength":500},"blocked_terms":{"type":"array","maxItems":200,"items":{"type":"string","minLength":2,"maxLength":120}}}}}},"TenantPolicyVersion":{"type":"object","nullable":true,"properties":{"version":{"type":"integer"},"status":{"type":"string","enum":["draft","published","archived"]},"policy":{"$ref":"#/components/schemas/TenantPolicy"},"content_hash":{"type":"string"},"notes":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"published_at":{"type":"string","format":"date-time","nullable":true},"archived_at":{"type":"string","format":"date-time","nullable":true}}},"ProtocolFreshness":{"type":"object","nullable":true,"description":"How current this protocol's knowledge is. `version` / `content_hash`\nidentify the ledger version you are reading (see\n/helix/protocols/{id}/versions); `corpus_version` moves whenever any\npublished knowledge changes (cached answers are keyed on it).\n`retracted_citations` / `flagged_citations` count cited papers that the\nscheduled PubMed integrity sweep found retracted or under an expression\nof concern since review; each opens a two-reviewer review.\n","properties":{"version":{"type":"integer","nullable":true},"content_hash":{"type":"string","nullable":true},"content_changed_at":{"type":"string","format":"date-time","nullable":true},"last_scanned_at":{"type":"string","format":"date-time","nullable":true},"last_verified_at":{"type":"string","format":"date-time","nullable":true},"corpus_version":{"type":"integer"},"retracted_citations":{"type":"integer"},"flagged_citations":{"type":"integer"}}},"HelixProtocolsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"compound":{"type":"string"},"protocol_count":{"type":"integer"},"protocols":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string"},"evidence_level":{"type":"string","nullable":true},"grade":{"type":"string","nullable":true,"enum":["A","B","C","D",null]},"fda_status":{"type":"string","nullable":true},"summary":{"type":"string","nullable":true},"indications":{"type":"array","items":{"type":"string"}},"freshness":{"$ref":"#/components/schemas/ProtocolFreshness"}}}}}}}},"ScribeHealthResponse":{"type":"object","description":"Two shapes. Without a valid partner key only status, service, version and timestamp are returned; uptime_seconds, capabilities and recommended_timeout_ms require a valid Authorization: Bearer key.","required":["status","service","version","timestamp"],"properties":{"status":{"type":"string","enum":["ok"]},"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"service":{"type":"string"},"uptime_seconds":{"type":"integer"},"capabilities":{"type":"array","items":{"type":"string"}},"recommended_timeout_ms":{"type":"integer"}}},"ScribeGenerateRequest":{"type":"object","required":["protocols"],"properties":{"protocols":{"type":"array","minItems":1,"maxItems":12,"description":"Protocol selections (1-12).","items":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Protocol or compound name."},"compound":{"type":"string","description":"Compound name (defaults to `name`)."},"dose":{"type":"string"},"frequency":{"type":"string"},"route":{"type":"string"},"duration":{"type":"string"}}}},"clinical_context":{"type":"string","maxLength":10000,"description":"Free-text clinical context for the note."},"note_format":{"type":"string","enum":["soap","dap","narrative"],"default":"soap"},"language":{"type":"string","enum":["en","ar"],"default":"en"},"lab_values":{"type":"array","description":"Optional lab values to include in the note.","items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"},"unit":{"type":"string"}}}},"previous_note_context":{"type":"string","description":"Text from a prior note for continuity."},"stream":{"type":"boolean","default":false,"description":"Request a Server-Sent Events stream instead of a buffered JSON response. Equivalent to sending `Accept: text/event-stream`. Progress `stage` events are followed by a single `content` event with the full note, then `done` with metadata.\n"}}},"ScribeGenerateResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"format":{"type":"string","enum":["soap","dap","narrative"]},"content":{"type":"string","description":"Full note text."},"sections":{"type":"object","additionalProperties":{"type":"string"},"description":"Note broken into named sections."},"protocols_summary":{"type":"string","nullable":true},"monitoring_plan":{"type":"string","nullable":true},"disclaimers":{"type":"array","items":{"type":"string"}},"confidence_score":{"type":"number","nullable":true},"interaction_alerts":{"type":"array","items":{"type":"string"}}}},"meta":{"type":"object","properties":{"latency_ms":{"type":"integer"},"protocol_count":{"type":"integer"},"language":{"type":"string"},"note_format":{"type":"string"}}}}},"HelixJobRequest":{"type":"object","required":["type","payload"],"properties":{"type":{"type":"string","enum":["query","scribe"],"description":"The job type. 'query' dispatches a Helix evidence query; 'scribe' generates a clinical note."},"payload":{"type":"object","description":"Job-specific payload. For type='query', mirrors HelixQueryRequest.\nFor type='scribe', mirrors ScribeGenerateRequest.\n","additionalProperties":true}}},"HelixJobCreatedResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string","enum":["pending"]},"type":{"type":"string","enum":["query","scribe"]},"estimated_ms":{"type":"integer","description":"Estimated processing time in milliseconds."},"poll_url":{"type":"string"}}}}},"HelixJobPendingResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"job_id":{"type":"string"},"type":{"type":"string"},"status":{"type":"string","enum":["pending"]},"elapsed_ms":{"type":"integer"},"estimated_ms":{"type":"integer","nullable":true}}}}},"HelixJobDoneResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"job_id":{"type":"string"},"type":{"type":"string"},"status":{"type":"string","enum":["done"]},"result":{"type":"object","description":"The full job result. Shape mirrors HelixQueryResponse.data (including `bottom_line`, `claims`, `evidence` and `citation_check`) or ScribeGenerateResponse.data depending on job type.","additionalProperties":true},"elapsed_ms":{"type":"integer"},"completed_at":{"type":"string","format":"date-time","nullable":true}}}}},"HelixJobFailedResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"job_id":{"type":"string"},"type":{"type":"string"},"status":{"type":"string","enum":["failed"]},"error":{"type":"string"}}}}},"V2ProtocolsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"count":{"type":"integer"},"category":{"type":"string","nullable":true},"q":{"type":"string","nullable":true}}}}},"V2CategoriesResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"count":{"type":"integer"}}}}},"InteractionCheckerRequest":{"type":"object","required":["medications","protocols"],"properties":{"medications":{"type":"array","minItems":1,"items":{"type":"string"},"description":"List of current medications (at least one required)."},"protocols":{"type":"array","minItems":1,"items":{"type":"string"},"description":"List of protocol compounds to check against (at least one required)."},"clientContext":{"type":"string","description":"Optional clinical context to improve interaction analysis accuracy."}}},"DrugInteraction":{"type":"object","properties":{"medication":{"type":"string"},"protocol":{"type":"string"},"severityLevel":{"type":"string","enum":["critical","major","moderate","minor","none"]},"description":{"type":"string"},"mechanism":{"type":"string"},"clinicalSignificance":{"type":"string"},"recommendation":{"type":"string","nullable":true},"evidence":{"type":"string"}}},"V2InteractionCheckerResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"interactions":{"type":"array","items":{"$ref":"#/components/schemas/DrugInteraction"}},"overallRiskLevel":{"type":"string","enum":["high","moderate","low"]},"safeProtocols":{"type":"array","items":{"type":"string"}},"cautionProtocols":{"type":"array","items":{"type":"string"}},"avoidProtocols":{"type":"array","items":{"type":"string"}},"summary":{"type":"string"},"monitoringRecommendations":{"type":"array","items":{"type":"string"}}}},"meta":{"type":"object","properties":{"checkedAt":{"type":"string","format":"date-time"},"compoundCount":{"type":"integer"},"latency_ms":{"type":"integer"}}}}}}}}