Endpoint Reference

Every v1 endpoint - method, path, headers, request/response schemas, and status codes

All endpoints are relative to the environment base URL (e.g. https://portal.your.md/api/v1). Unless stated otherwise, every request requires:

x-api-key: <api_key>
Authorization: Bearer <access_token>     (upgraded token for assessment endpoints)
Content-Type: application/json           (when a body is sent)

Error responses share a single format — see Errors, Limits & Timeouts.


Authentication & legal

POST /login

Exchange partner credentials for a session token. The only endpoint that does not need Authorization (the x-api-key header is still required).

Request body:

FieldTypeRequiredNotes
partner_idstringyesIssued by Healthily
secretstringyesIssued by Healthily

Optional header: X-Language (default en-US; must be enabled for your partner — otherwise 400 "Language ... is not allowed").

Response 200:

{ "access_token": "eyJ...", "token_type": "bearer", "expires_in": 1860 }

Errors: 400 missing fields · 401 bad credentials.

GET /terms

Fetch the legal content to display. Requires the initial token.

Response 200: content_version, messages[], checkbox_policies[], footer_policies[] — see Legal & Consent.

POST /terms

Record consent; returns the upgraded token.

Request body:

FieldTypeRequired
content_versionstringyes — exactly as returned by GET /terms
all_policies_acceptedbooleanyes — must be true to proceed

Response 200: login_response (new token) + onboarding_response (age_question, gender_question, symptoms_question).


Consultation

POST /initial

Start the assessment. Requires the upgraded token.

Request body:

FieldTypeRequiredConstraints
genderstringyese.g. male, female (use ids from onboarding_response.gender_question)
ageintegeryes18–125
initial_querystringyesfree text, 3–500 characters

Response 200: a ChatResponse with the first question.

POST /chat

Answer the current question; returns the next question (or a state where the report is available).

Request body:

FieldTypeRequiredNotes
typestringyesThe type of the question being answered: generic, symptom, symptoms, symptoms_choose_one, factor, health_background, or autocomplete
includedstring[]see noteChoice ids the user selected
excludedstring[]see noteChoice ids the user saw but did not select

At least one of included/excluded must be non-empty. Selections must come from the current question's choices and respect its constraints.min_selections/max_selections; otherwise 400.

Response 200: ChatResponse.

GET /chat

Return the current state (latest question or final state) without advancing the conversation. Use for UI restore after refresh/resume, for recovery after a timed-out POST /chat, and to re-read the final state after conversation_ended.

Response 200: ChatResponse. 404 if no conversation exists for this session yet.

POST /step-back

Undo the last answered question. Empty body.

Precondition: latest response had conversation_details.step_back_possible: true.

Response 200: ChatResponse re-rendering the previous question.

GET /report

Generate/fetch the final report.

Precondition: conversation_details.report_possible: true — calling earlier returns 400 ("Report generation not allowed at this point").

Response 200:

{
  "conversation_details": { "conversation_ended": true, ... },
  "report": { ... }        // PatientReport — see Reports chapter
}

See Reports for the full report schema.


Search

GET /symptom-search

Symptom autocomplete, for driving a type-ahead search box during the autocomplete phase.

Query parameters:

ParamRequiredConstraints
textyes1–100 characters
gendernofilter results by gender relevance

Response 200:

{
  "user_facing_prefix": "also known as",
  "autocomplete": [
    {
      "id": "assessment_C0231749",
      "cui": "C0231749",
      "dropdown_name": "Jaw clicking (Clicking noises from jaw)",
      "display_name": "Jaw clicking",
      "highlight": "Jaw <i>clicking</i> (Clicking noises from jaw)"
    }
  ]
}
  • dropdown_name — show in the suggestion list; highlight is the same string with the matched term wrapped in <i>…</i> for emphasis.
  • display_name — show once selected (as a chip/tag).
  • id — send this (not cui) as the included value of the autocomplete answer.

This is a fast endpoint (server timeout 3 s) intended to be called on each keystroke (debounce client-side — remember the per-partner rate limits).


Content

GET /articles?ids=<id1>,<id2>,...

Fetch up to 20 full articles by id (ids come from report information_articles and condition articles).

Response 200: { "articles": [ ... ] } with full article content (paragraphs, images, contributors, metadata).

GET /article/{id}

Fetch a single full article.

Response 200: the article object. 404 if unknown.


Analytics & feedback (optional but recommended)

POST /analytics

Fire-and-forget UI interaction events (helps Healthily and you analyse funnel behaviour).

{ "event": "accordion_item_opened", "value": { "gender": "male", "age": "31" } }
  • event (string, required); value optional — any JSON (string/array/object), total size limited (~1000 characters; oversized payloads are rejected).

Response 200 (accepted asynchronously).

POST /analytics/feedback

End-of-assessment user feedback.

{ "stars": 5, "labels": ["Fast", "Responsive"], "message": "I liked it" }
FieldConstraints
starsrequired, 1–5
labelsoptional, max 8 strings
messageoptional, max 1000 characters

ChatResponse shape

Returned by POST /initial, POST /chat, GET /chat, and POST /step-back. Empty/null fields are omitted.

{
  "conversation_details": {
    "step_back_possible": true,
    "report_possible": false,
    "scenario": "CONSULTATION_QUESTIONS",
    "conversation_ended": false,
    "symptoms_summary": {
      "selected": [ { "cui": "C0018621", "name": "Earache" } ],
      "excluded": [ { "cui": "C0006325", "name": "Bruxism" } ],
      "ignored":  []
    },
    "progress": { "stage": "Symptoms Assessment", "percentage": 30 }
  },
  "question": {
    "type": "symptoms",
    "id": "q-123",
    "messages": [
      { "value": "Do you have any of the following?", "type": "HEADER", "format": "PLAIN_TEXT" }
    ],
    "choices": [
      { "id": "C0041105", "text": "Ringing in the ears" },
      { "id": "C0018681", "text": "Headache",
        "symptom_definition": { "value": "Pain anywhere in the head...", "type": "PARAGRAPH", "format": "PLAIN_TEXT" } }
    ],
    "constraints": { "min_selections": 0, "max_selections": 4 }
  },
  "report": null
}
  • question — present while there is something to ask. See Questions & Answers for every question type and how to render it.
  • report — present when the flow terminates directly with a report payload; in the normal consultation flow you fetch the report via GET /report once report_possible is true.
  • debug_messages — internal diagnostics; only present for partners with debug enabled. Never show to end users.