Phenotype Classify
Status:
stableCategory:compositeAdded:2026-04-20Last reviewed:2026-10-11
Summary
A pattern-first path for callers that want the phenotype classification and its
recommendations without the scoring envelope. The body is the same flat
answers array /cdri/compute takes; the
response is phenotype, confidence and recommendations only — no
cdri score block, no phenotypes channel readings, no breadth, no
acuity.
This is the home of recommendations. /cdri/compute publishes a
measurement and nothing derived from it, so if you want suggested next steps —
including escalations — this is the endpoint that produces them.
⚠ Not a clinical diagnosis
The phenotype is a statistical summary, not a diagnosis. See composite-cdri-compute.md.
Endpoint
| Field | Value |
|---|---|
| Method | POST |
| Path | /api/phenotype/classify |
| Full URL | https://engine.tripod-health.com/api/phenotype/classify |
| Authentication | API key (required) |
| Request body | application/json |
| Rate-limited | Yes |
There is no ?depth= parameter on this endpoint.
Request
Same headers and body shape as
/cdri/compute — a flat answers array of
{item_id, value} objects, plus optional demographics and role. This
endpoint does not take case, because it publishes no acuity.
It also takes an optional assist_context: the persona and instructions for the
audience-framed ai_summary and per-item message text (on-demand
references are rejected). Both texts pass the engine's outbound identifier
scan; a summary that fails it comes back null, and a message that fails it
leaves that item's message null.
Query parameters
| Param | Default | Values | Description |
|---|---|---|---|
recommend | rich | rich | simple | rules | off | Controls the recommendations layer. See Recommendation modes. |
audience | (unset) | provider | employee | employer | Steers the audience-framed narrative text. When unset, narrative output stays null. |
Recommendation modes
| Mode | What runs | ai_summary | Per-item message |
|---|---|---|---|
rich (default) | Rules, then an AI summary and per-item humanization. | Present | Present |
simple | Rules, then an AI summary only. Items stay templated. | Present | null |
rules | Rules only. No model call, so it is deterministic and cheaper in latency. | null | null |
off | No recommendations block on the response at all. | — | — |
Use rules when you render the action and rationale text yourself, and
rich when you want prose a person can read directly. rules is the right
default for a machine consumer.
Response
Success — 200 OK
A real capture under ?recommend=rules, from the ten-answer body in
/cdri/compute:
{
"phenotype": {
"backend": "deterministic",
"model_version": "2026-09-15-standard-ladder",
"phenotype": "rtw_barrier",
"distribution": {
"pain_dominant": 0.1521,
"psychosocial_dominant": 0.1539,
"fear_avoidance_dominant": 0.152,
"rtw_barrier": 0.1847,
"multi_domain_catastrophic": 0.1304,
"iatrogenic_escalation": 0.0547,
"established_chronicity": 0.1722
},
"model_certainty": 0.1847,
"overall_level": 0.7951,
"trajectory": null,
"similar_cases": null,
"anomalies": null
},
"confidence": {
"overall": 0.4587,
"tier": "medium",
"breakdown": {
"evidence": 0.6332847231817376,
"input_completeness": null,
"imputation_variance": 0.5,
"model_certainty": 0.1847
}
},
"recommendations": {
"engine_version": "1.0.0",
"ruleset_version": "1.0.0",
"disclaimer": "The Trinity Engine is a decision-support tool. Output is not medical advice, not a diagnosis, not a prescription, and not a benefits determination. The calling organization is responsible for clinical governance and for the interpretation and use of these suggestions.",
"ai_summary": null,
"items": [
{
"id": "r_033d0ad2bdb35966",
"rule_id": "rec.data_acquisition.phenotype_top2_ambiguity",
"rule_version": "1.0.0",
"priority": "high",
"category": "data_acquisition",
"item_disclaimer": "Consider, not prescribe.",
"clinical_source": null,
"fired_under": {
"confidence_tier": "medium",
"phenotype_certainty": 0.1847
},
"action_type": "ask_questions",
"action": "Ask more about 'rtw_barrier' before acting on the pattern. POST /api/cdri/questions?phenotype=rtw_barrier&order=voi returns the bank questions that channel leads, ranked by how much confidence each one buys, and answering them is what widens the top-two gap.",
"target": {
"phenotype": "rtw_barrier",
"questions_url": "/api/cdri/questions?phenotype=rtw_barrier&order=voi"
},
"rationale": "Top phenotype 'rtw_barrier' at 0.18 is close to the second class at 0.17 (gap 0.01); certainty 0.18 is below the 0.45 threshold. Two patterns this close are not separable from the answers given so far.",
"triggers": {
"phenotype.model_certainty": 0.1847,
"phenotype.top_name": "rtw_barrier",
"phenotype.top_gap": 0.013
},
"expected_impact": {
"metric": "phenotype.model_certainty",
"direction": "increase"
},
"followup": {
"type": "recompute",
"endpoint": "/api/phenotype/classify",
"guidance": "Re-classify once the new answers are added to answers."
},
"message": null
}
],
"suppressed": [
{
"rule_id": "rec.clinical_action.rtw_barrier_fce_graduated",
"reason": "threshold_not_met",
"details": "Confidence tier 'medium' is blocked for clinical-action emission."
}
],
"cardinality_cap": null
},
"depth": "full",
"catalog_version": "0.36.0",
"request_id": "b1f2c3d4-5678-90ab-cdef-1234567890ab",
"timestamp": "2026-09-16T01:05:31.402118+00:00"
}
The phenotype and confidence blocks are identical in shape to their
counterparts on /cdri/compute:
recommendations
| Field | Type | Always present | Description |
|---|---|---|---|
engine_version | string | Yes | Version of the recommendation engine. |
ruleset_version | string | Yes | Version of the rule set that ran. |
disclaimer | string | Yes | Applies to the whole block. Surface it wherever you surface items. |
ai_summary | string | null | Yes | Prose across the items. null under rules. |
items | array | Yes | The recommendations that fired. Empty is a valid result. |
suppressed | array | Yes | Rules that matched their domain and then declined to fire. See below. |
cardinality_cap | integer | null | Yes | Set when items were trimmed to a cap. |
A recommendation item
| Field | Type | Always present | Description |
|---|---|---|---|
id | string | Yes | Stable per firing. Use it to de-duplicate in a UI. |
rule_id | string | Yes | Which rule produced it. Safe to branch on. |
rule_version | string | Yes | Version of that rule. |
priority | string | Yes | urgent, high, or routine. The ordering signal for a UI. |
category | string | Yes | escalation, clinical_action, data_acquisition, caution, or monitoring. |
item_disclaimer | string | Yes | Per-item qualifier, for example "Consider, not prescribe." |
clinical_source | object | null | Yes | A citation when the rule rests on published guidance; null for an internal heuristic. |
fired_under | object | Yes | The confidence state at firing, so you can filter on your side. |
action_type | string | Yes | A short machine token for the kind of action. |
action | string | Yes | What to do, in prose. |
target | object | Yes | The specific subject of the action. Shape varies by action_type. |
rationale | string | Yes | Why it fired, with the numbers it fired on. |
triggers | object | Yes | The exact values that satisfied the rule. |
expected_impact | object | Yes | Which metric the action should move, and in which direction. |
followup | object | null | Yes | How to close the loop — endpoint and guidance. |
message | string | null | Yes | Humanized text under rich; null otherwise. |
suppressed is not an error list. A rule appears there when it matched the
situation but declined to emit — most often because confidence was too low to
responsibly suggest a clinical action. reason is one of
threshold_not_met, data_unavailable, or
overridden_by_higher_priority. Reading it tells you what would have fired
with better evidence, which is usually more useful than the empty space.
Escalations are items, not a separate array
There is no red_flags array. A safety escalation is a recommendation item
with category: "escalation" and priority: "urgent". Filter for those two
rather than looking for a dedicated field.
const urgent = result.recommendations.items.filter(
(item) => item.category === "escalation" && item.priority === "urgent",
);
Degraded phenotype — 200 OK with backend: "none"
When the classifier cannot produce a phenotype, the shape is identical but
every inner phenotype field is null:
{
"phenotype": {
"backend": "none",
"model_version": null,
"phenotype": null,
"distribution": null,
"model_certainty": null,
"overall_level": null,
"trajectory": null,
"similar_cases": null,
"anomalies": null
},
"confidence": {
"overall": 0.5,
"tier": "medium",
"breakdown": {
"evidence": null,
"input_completeness": null,
"imputation_variance": 0.5,
"model_certainty": null
}
},
"recommendations": {
"engine_version": "1.0.0",
"ruleset_version": "1.0.0",
"disclaimer": "The Trinity Engine is a decision-support tool. Output is not medical advice, not a diagnosis, not a prescription, and not a benefits determination. The calling organization is responsible for clinical governance and for the interpretation and use of these suggestions.",
"ai_summary": null,
"items": [],
"suppressed": [],
"cardinality_cap": null
},
"depth": "full",
"catalog_version": "0.36.0",
"request_id": "docs-phenotype-degraded",
"timestamp": "2026-09-16T00:00:00.000000+00:00"
}
The status stays 200. Most phenotype-conditional rules cannot fire without a
phenotype, so items is usually empty here.
Status codes
Same as /cdri/compute.
Examples
The snippets assume the call() helper from
quickstart.md.
curl
curl -sS -X POST "https://engine.tripod-health.com/api/phenotype/classify?recommend=rules" \
-H "apikey: $ENGINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"answers": [{"item_id": "pain_intensity_now", "value": 5}, {"item_id": "expect_usual_work_6_months", "value": 4}, {"item_id": "modified_duty_available", "value": 6}]}'
Python (requests)
# Uses the call() helper from quickstart.md.
result = call("POST", "/api/phenotype/classify?recommend=rules", {"answers": answers})
ph = result["phenotype"]
print(f"phenotype: {ph['phenotype']} (certainty {ph['model_certainty']})"
if ph["phenotype"] else "phenotype: unavailable")
for item in result["recommendations"]["items"]:
marker = "URGENT" if item["priority"] == "urgent" else item["category"]
print(f" [{marker}] {item['action']}")
Node.js (native fetch)
// Uses the call() helper from quickstart.md.
const result = await call(
"POST", "/api/phenotype/classify?recommend=rules", { answers },
);
const ph = result.phenotype;
console.log(ph?.phenotype
? `phenotype: ${ph.phenotype} (certainty ${ph.model_certainty})`
: "phenotype: unavailable");
TypeScript
// CdriResponse from composite-cdri-compute.md is a superset of this
// endpoint's response — reuse it minus the scoring blocks, plus
// recommendations, which /cdri/compute does not return.
type PhenotypeResponse = Omit<
CdriResponse,
"composite_id" | "cdri" | "phenotypes" | "breadth" | "acuity"
> & {
recommendations: RecommendationSet | null;
};
Intended use
- Getting suggested next steps. This is the only endpoint that returns them.
- A lean pattern read. When a UI renders the phenotype label and an action list and nothing else, this skips the scoring blocks.
- Closing the ambiguity loop. A low
model_certaintyproduces adata_acquisitionitem naming the exact/cdri/questionscall that would sharpen it; follow it and re-classify. - Mobile or low-bandwidth callers where payload size matters.
Mistaken use
- Do not use this for a severity readout — it carries no
cdriscore and no per-channel levels. Use/cdri/compute. - Do not look for
red_flags. Escalations are items; filter oncategoryandpriority. - Do not treat
phenotype.phenotypeas a diagnosis — display it alongsidemodel_certainty, which is frequently low. - Do not treat an empty
itemsarray as "nothing to do". Readsuppressed: a clinical action withheld for low confidence is a prompt to gather more, not an all-clear. - Do not cache by request-body hash under
richorsimple— those modes make a model call and the prose can vary across identical calls. - Do not submit an instrument's responses. The body is bank answers. To
score a published instrument, use its own
/scoreendpoint.
Related
- composite-cdri-compute.md — the full scored result, same body, no recommendations.
- composite-cdri-questions.md — where a
data_acquisitionitem points you. - composite-cdri-extract.md — answers mined from a visit transcript.
- credits.md —
richandsimplemake a model call;rulesdoes not.
Change history
| Date | Change |
|---|---|
| 2026-04-20 | Initial publication. |
| 2026-06-03 | Documented the degraded phenotype shape. |
| 2026-09-16 | Body is a flat answers array of bank questions; instruments is gone. red_flags removed — escalations are recommendation items. overall_magnitude renamed overall_level, and confidence.breakdown now reports evidence with input_completeness always null. This page now owns the recommendation-mode and item documentation, which /cdri/compute no longer returns. |
| 2026-10-11 | Accepts assist_context for the audience narrative text, which now passes the outbound identifier scan. |