Integration Walkthrough
A complete worked consultation, request by request, with an integration checklist
A complete consultation, request by request, based on the reference scenario ("earache, jaw clicks") from the official healthily-api-examples Bruno collection. Base URL: https://portal.your.md/api/v1 (production).
Throughout: x-api-key: <api_key> on every call; Authorization: Bearer <token> on everything after login.
0. Prerequisite: your own user gate
Before any of this, your application has authenticated its own user and decided they may run an assessment. All calls below are made by your backend with partner credentials — see Authentication.
1. Login
POST /api/v1/login
x-api-key: <api_key>
{ "partner_id": "<partner_id>", "secret": "<partner_secret>" }→ { "access_token": "<token-1>", "token_type": "bearer", "expires_in": 1860 }
2. Fetch and display terms
GET /api/v1/terms
Authorization: Bearer <token-1>→ render messages, checkbox_policies (with checkboxes), keep footer_policies visible; remember content_version.
3. Record consent → upgraded token
POST /api/v1/terms
Authorization: Bearer <token-1>
{ "content_version": "<content_version>", "all_policies_accepted": true }→ login_response.access_token = <token-2> (use from now on), plus onboarding_response with ready-made age/gender/symptom question content for your onboarding screen.
4. Start the assessment
Collect gender, age, and a free-text description, then:
POST /api/v1/initial
Authorization: Bearer <token-2>
{ "gender": "male", "age": 31, "initial_query": "earache, jaw clicks" }→ a ChatResponse. In this scenario the engine recognises earache and jaw clicking and responds with a symptoms ratification question ("Do you have any of the following?") listing recognised and related symptoms as choices, each possibly carrying symptom_definition helper copy.
5. The chat loop
Render each question from type + messages + choices + constraints; submit the user's selection; repeat. The actual sequence for this scenario:
5a. Health background — user has none of the listed conditions:
POST /api/v1/chat
{ "type": "health_background",
"included": [],
"excluded": ["C0011849", "C0004096", "C0010054", "C0403447", "C0024117",
"C0038454", "C0020538", "C0028754", "C0337664"] }5b. Symptoms follow-up — has tinnitus, doesn't have the other three:
POST /api/v1/chat
{ "type": "symptoms",
"included": ["C0041105"],
"excluded": ["C0006325", "C0018681", "C0015468"] }5c. Duration — about a year:
POST /api/v1/chat
{ "type": "generic",
"included": ["year"],
"excluded": ["hour", "day", "week", "month"] }5d–5f. Further diagnostic questions — more symptoms/symptom/factor turns, plus a ratification confirmation and a continue assessment vs add more symptoms choice, all answered the same way. Watch conversation_details.progress to drive your progress bar, and step_back_possible to enable/disable a Back button.
After the last question the response has no further question and conversation_details.report_possible: true.
6. Fetch the report
GET /api/v1/report
Authorization: Bearer <token-2>For this scenario the report's headline is:
"overall_outcome": {
"subdomain_triage_level": { "display_name": "Non-urgent", "triage_level_color": "BLUE" },
"main_service_recommendation": "General Practitioner",
...
}with a LIKELY subdomain (stress/tension-related, CM001889) containing the matched condition and its article card. Render per Reports: headline (colour-coded) → to-rule-out → likely → also-considered → other options → summary → articles → disclaimers.
7. Optional: feedback
POST /api/v1/analytics/feedback
{ "stars": 5, "labels": ["Fast", "Clear"], "message": "Helpful!" }Variations you must support
A. Autocomplete (symptom not recognised, or adding symptoms)
When the response question has type: "autocomplete", show a search box. As the user types (debounced):
GET /api/v1/symptom-search?text=ear%20ache→ suggestion list from autocomplete[] (dropdown_name / highlight in the dropdown, display_name once chosen). Answer with the suggestion's id:
POST /api/v1/chat
{ "type": "autocomplete", "included": ["assessment_C2316035"] }The question may also offer add another / skip choices — send their ids like any other choice.
B. Step back
If step_back_possible: true, a Back button issues:
POST /api/v1/step-back (empty body)→ the previous question re-renders; the user answers again and the flow continues from there.
C. Clarifications and red flags
Ambiguous symptoms produce generic clarify questions (choice ids like A290201); rule-out questions look like normal questions. No special handling — your generic renderer covers them.
D. No-outcome endings
Insufficient input, a single non-specific symptom, informational intent, or no matching cause all end in message-driven outcomes (sometimes with a RESTART action) rather than a condition list — see edge-case outcomes. Test all of them.
E. Session recovery
On page refresh / app resume: GET /api/v1/chat re-renders the current question. On 401: session expired — restart from login with a clear message to the user.
Integration checklist
Security & auth
-
partner_id,secret,api_keylive only on your server - API calls proxied through your backend, behind your own user auth
- Upgraded (post-terms) token used for all assessment calls
-
401handled as session restart, with user messaging
Legal
- Terms fetched, rendered, and accepted before assessment
-
content_versionechoed exactly; footer policies persistently visible - Report
disclaimer_messagesalways rendered
Conversation UI
- One generic question renderer driven by
type/messages/choices/constraints -
symptom_definitionshown as helper copy when present - Unselected choices sent in
excluded - Autocomplete flow wired to
/symptom-search(debounced) - Back button gated on
step_back_possible; progress bar fromprogress -
GET /chatused for restore and post-timeout recovery (no blind retries ofPOST /chat)
Report
- Triage colour/urgency rendered prominently, never re-ranked
- All subdomain categories handled (
TO_RULE_OUT,LIKELY,ALSO_CONSIDERED) -
actiontypes implemented (PHONE_NUMBER,EMAIL,URL,RESTART) - All edge-case outcomes (information / not possible / no cause / workaround) tested
Operations
- Rate limits respected (throttle in your backend; debounce search)
- Timeouts configured per endpoint; backoff on
429/5xx - Daily quota sized against expected volume
Testing
Healthily maintains a Bruno collection (healthily-api-examples) with all of the scenarios above as runnable requests. With Bruno CLI:
npx bru run Scenarios -r --env Healthily-staging \
--env-var partner_id="$PARTNER_ID" \
--env-var partner_secret="$PARTNER_SECRET" \
--env-var api_key="$API_KEY"Run it against staging while developing, and consider wiring the same scenarios into your CI as a nightly contract check.
