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

{
            "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": []
        }
FieldRender as
subdomain_triage_level.display_nameThe urgency headline (e.g. "Emergency", "Urgent", "Non-urgent", "Self-care")
subdomain_triage_level.triage_level_colorColour-code the headline: RED, AMBER, BLUE, GREEN, BLACK, NONE
main_recommendationThe primary advice sentence
main_service_recommendationThe recommended care service (e.g. "General Practitioner", "Pharmacy")
messages / instructionsSupporting copy — render in order
actionA call-to-action button; see below

Actions

{ "label": "Call emergency services", "type": "PHONE_NUMBER", "value": "999" }

typePHONE_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:

LevelTypical displayColour
emergency_ambulance, emergency_aeEmergencyRED
urgent_12h, urgent_48hUrgentAMBER
routineNon-urgentBLUE
self_care, self_limitingSelf-careGREEN
workaround, no_outcomeNo outcome / InformationBLACK

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

Conditions 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_typeTO_RULE_OUT | LIKELY | ALSO_CONSIDERED. TO_RULE_OUT is the safety-critical category — conditions the user should actively exclude with a professional; render it above/ahead of "likely".
  • Each condition may include an article with a snippet, next-steps triage_messages, and an information_article card whose id can be passed to GET /articles for 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

Alternative 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

Pre-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

Related 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

A 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:

OutcomeWhat you'll seeWhat to render
Information reportoverall_outcome with an information-style triage (display_name like "Information", colour BLACK) and information_articles; no/empty condition categoriesThe messages + article cards; this happens when the user's intent was informational rather than symptomatic
Assessment not possibleOutcome messages explaining the assessment couldn't be completed, often with a RESTART actionThe explanation + restart CTA (new login required)
No cause foundSymptoms were understood but no condition matchedOutcome messages + any articles; advise professional consultation per the provided copy
Single symptom / highly non-pathologicalA "workaround" outcome: general advice + articles instead of a differentialMessages + 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.