Reports
The final report structure - triage levels, conditions, care recommendations, and edge-case outcomes
GET /report (allowed once conversation_details.report_possible is true) returns the consultation outcome:
{
"conversation_details": { "conversation_ended": true, "scenario": "CONSULTATION_REPORT", ... },
"report": { ... }
}The report object is a patient-facing, presentation-ready structure: the API has already turned the diagnostic engine's output into display messages, ordered sections, colours, and calls-to-action. Your job is to render it faithfully — especially triage levels and disclaimers.
Report structure overview
report
├── overall_outcome ← headline: triage level, recommendation, action
├── subdomains_container ← possible causes, grouped by category
├── other_options ← alternative care options (cards with actions)
├── summary ← what the user told us (age, symptoms, answers)
├── information_articles ← related self-care / information articles
└── disclaimer_messages ← legal/medical disclaimers (must render)
overall_outcome — the headline
overall_outcome — the headline{
"subdomain_triage_level": {
"display_name": "Urgent",
"triage_level_color": "AMBER"
},
"main_recommendation": "Suggested next step:",
"main_service_recommendation": "Urgent Care Centre today",
"messages": [
{
"value": "Based on your reported symptoms and health information, it’s recommended you go to the nearest **Urgent Care Centre today** for an **urgent** in person assessment. Urgent care centres treat injuries and illnesses that need urgent treatment on the same day but do not need the services of an emergency department.",
"type": "PARAGRAPH",
"format": "MARKDOWN"
},
{
"value": "If your symptoms change or worsen please seek medical advice.",
"type": "PARAGRAPH",
"format": "MARKDOWN"
}
],
"action": {
"label": "Find your nearest Urgent Care Centre",
"type": "URL",
"value": "https://www.nhs.uk/nhs-services/urgent-and-emergency-care-services/find-urgent-and-emergency-care-services/"
},
"instructions": []
}| Field | Render as |
|---|---|
subdomain_triage_level.display_name | The urgency headline (e.g. "Emergency", "Urgent", "Non-urgent", "Self-care") |
subdomain_triage_level.triage_level_color | Colour-code the headline: RED, AMBER, BLUE, GREEN, BLACK, NONE |
main_recommendation | The primary advice sentence |
main_service_recommendation | The recommended care service (e.g. "General Practitioner", "Pharmacy") |
messages / instructions | Supporting copy — render in order |
action | A call-to-action button; see below |
Actions
{ "label": "Call emergency services", "type": "PHONE_NUMBER", "value": "999" }type ∈ PHONE_NUMBER (tel: link), EMAIL (mailto:), URL (open link), RESTART (offer to begin a new assessment — which requires a new login).
Triage levels
The underlying urgency scale, from most to least urgent:
| Level | Typical display | Colour |
|---|---|---|
emergency_ambulance, emergency_ae | Emergency | RED |
urgent_12h, urgent_48h | Urgent | AMBER |
routine | Non-urgent | BLUE |
self_care, self_limiting | Self-care | GREEN |
workaround, no_outcome | No outcome / Information | BLACK |
You normally consume the pre-rendered display_name + triage_level_colorrather than the raw enum. Never downgrade, hide, or re-order urgency: emergency outcomes must be the first and most prominent thing the user sees.
subdomains_container — possible causes
subdomains_container — possible causesConditions are grouped into categories, each category into subdomains (symptom areas), each subdomain into concrete conditions:
{
"messages": [ { "value": "Possible causes", "type": "HEADER", "format": "PLAIN_TEXT" } ],
"subdomains_categories": [
{
"subdomain_type": "LIKELY",
"subdomain_category_color": "BLUE",
"messages": [ { "value": "Most likely causes", "type": "HEADER", "format": "PLAIN_TEXT" } ],
"subdomains": [
{
"label": "1",
"cui": "CM001889",
"name": "Stress or tension related",
"subdomain_triage_level": { "display_name": "Non-urgent", "triage_level_color": "BLUE" },
"primary_service": "General Practitioner",
"trigger_details": [ { "value": "Based on: earache, jaw clicking", "type": "PARAGRAPH", "format": "PLAIN_TEXT" } ],
"conditions": [
{
"cui": "C0039494",
"name": "Temporomandibular joint disorder",
"level": { "display_name": "Non-urgent", "triage_level_color": "BLUE" },
"primary_service": "General Practitioner",
"trigger_details": [ ... ],
"article": {
"name": "TMJ disorders",
"content": {
"name": "TMJ disorders",
"medical_name": "Temporomandibular disorder",
"snippet": "Problems with the jaw joint and surrounding muscles...",
"triage_messages": [ { "messages": [ ... ] } ]
},
"information_article": {
"id": "con-tmj-disorders",
"name": "TMJ disorders",
"snippet": "...",
"image": "https://...",
"reading_time_minutes": 5
}
},
"superdomain_cui": "CM001889",
"superdomain_name": "Stress or tension related"
}
]
}
]
}
]
}subdomain_type∈TO_RULE_OUT|LIKELY|ALSO_CONSIDERED.TO_RULE_OUTis the safety-critical category — conditions the user should actively exclude with a professional; render it above/ahead of "likely".- Each condition may include an
articlewith a snippet, next-stepstriage_messages, and aninformation_articlecard whoseidcan be passed toGET /articlesfor the full content. - The API does not expose numeric probabilities — the ordering and category grouping is the ranking. Preserve the given order.
Here's how the report.subdomains_container should be rendered:
Below, see the how a response with a single subdomain should be rendered.
The information icon should be clickable and should expose the conditions array of each subdomain.

Here's how the popup should look when the subdomain has multiple conditions:
First screen:
When clicking on Learn more about this condition, the following pop up is displayed. If the subdomain has a single condition, you can skip the first screen and show this directly:
When clicking on the article button, a /GET article request should be made using the information_article.id to get the full content. That should be also rendered in a pop up.
other_options
other_optionsAlternative care options rendered as cards:
{
"messages": [ { "value": "Other things you can do", "type": "HEADER", "format": "PLAIN_TEXT" } ],
"options": [
{ "messages": [ { "value": "Speak to a pharmacist...", "type": "PARAGRAPH", "format": "PLAIN_TEXT" } ],
"action": { "label": "Find a pharmacy", "type": "URL", "value": "https://..." } }
]
}
summary — what the user reported
summary — what the user reportedPre-formatted recap of the consultation input (age, gender, duration, included and excluded symptoms), as display messages grouped into containers:
{
"messages": [ { "value": "Your answers", "type": "HEADER", "format": "PLAIN_TEXT" } ],
"summary_containers": [
{ "items": [ { "value": "Age: 31", "type": "BULLET_POINT", "format": "PLAIN_TEXT" },
{ "value": "Reported: earache, jaw clicking", "type": "BULLET_POINT", "format": "PLAIN_TEXT" } ] }
]
}Useful for a "review your answers" section and for the user to sanity-check what the assessment was based on.
information_articles
information_articlesRelated reading, as lightweight cards:
{
"messages": [ { "value": "Related articles", "type": "HEADER", "format": "PLAIN_TEXT" } ],
"information_articles": [
{ "id": "con-earache", "name": "Earache", "snippet": "...",
"image": "https://...", "reading_time_minutes": 4 }
]
}Fetch full article bodies with GET /articles?ids=... (max 20 per call) or GET /article/{id}.
disclaimer_messages
disclaimer_messagesA list of Message objects with the legal/medical disclaimers for the report ("this is not a diagnosis", etc.). Rendering these with the report is mandatory — do not truncate or hide them.
Edge-case outcomes
Not every consultation ends with a ranked condition list. Your UI must handle all of these:
| Outcome | What you'll see | What to render |
|---|---|---|
| Information report | overall_outcome with an information-style triage (display_name like "Information", colour BLACK) and information_articles; no/empty condition categories | The messages + article cards; this happens when the user's intent was informational rather than symptomatic |
| Assessment not possible | Outcome messages explaining the assessment couldn't be completed, often with a RESTART action | The explanation + restart CTA (new login required) |
| No cause found | Symptoms were understood but no condition matched | Outcome messages + any articles; advise professional consultation per the provided copy |
| Single symptom / highly non-pathological | A "workaround" outcome: general advice + articles instead of a differential | Messages + articles as given |
The uniform rule: render whatever sections are present, in the order given, and rely on messages for the explanation — the API always sends display-ready copy for these states.
After the report
conversation_ended is true. GET /chat (and GET /report) still return the final state, but no further answers are accepted. A new assessment — e.g. via a RESTART action — starts from POST /login again.
