Claim Complexity Prediction
Status:
betaCategory:claimcomplexityAdded:2026-08-07Last reviewed:2026-08-07
Summary
Predict whether a New York workers' compensation claim is likely to become procedurally complex — administratively involved, with hearings, repeated independent medical exams, or alternative dispute resolution — from six de-identified early-claim attributes. Returns a label, a confidence, and the full probability distribution.
This is a research proxy trained on the New York Workers' Compensation Board public dataset. It is not an official WCB designation, not a severity score, and not a cost estimate. It predicts administrative friction, not medical difficulty.
Endpoint
| Field | Value |
|---|---|
| Method | POST |
| Path | /api/claimcomplexity/predict |
| Full URL | https://engine.tripod-health.com/api/claimcomplexity/predict |
| Authentication | API key (required) |
| Request body | application/json |
| Response body | application/json |
| Idempotent | Yes (deterministic classifier — the same input yields the same output) |
| Rate-limited | Yes |
Purpose
Use this endpoint to triage a book of claims by likely administrative burden: which files are likely to generate hearings and IME cycles, and therefore warrant earlier adjuster attention or proactive resolution.
It answers a different question from
/api/claimcost/classify. Cost and procedural
complexity correlate but are not the same thing — a cheap claim can be
procedurally brutal, and an expensive one can settle without a hearing. Call
both if you need both.
The accepted gender codes and industry_title strings are fixed and
exact-match. Fetch them from
GET /api/claimcomplexity/options and validate
against that list; an unrecognized value returns 400.
Authentication
Send a valid API key in the apikey header. A missing or unknown key returns
401 Unauthenticated at the gateway before the request reaches the engine. See
authentication.
Request
Headers
| Header | Required | Description |
|---|---|---|
apikey | Yes | Consumer API key. |
Content-Type | Yes | Must be application/json. |
Path parameters
None.
Query parameters
None.
Body
All six features are required and live under a single features object.
{
"features": {
"age_at_injury": 44,
"average_weekly_wage": 900,
"birth_year": 1982,
"accident_month": 4,
"gender": "M",
"industry_title": "Construction"
}
}
Body fields
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
features | object | Yes | — | Container for the six model inputs. |
features.age_at_injury | number | Yes | 0 ≤ v ≤ 120 | The worker's age in years at the time of injury. |
features.average_weekly_wage | number | Yes | 0 ≤ v ≤ 10000000 | Average weekly wage in US dollars. |
features.birth_year | number | Yes | 1900 ≤ v ≤ 2100 | Four-digit year of birth. Year only — never a full date. |
features.accident_month | integer | Yes | 1 ≤ v ≤ 12 | Calendar month of the accident, 1 = January. Month only — never a full date. |
features.gender | string | Yes | 1–200 chars, must match an accepted code | One of the genders values from options (F, M, U, X). |
features.industry_title | string | Yes | 1–200 chars, must match an accepted value | One of the industries values from options, matched on the full string. |
birth_year and accident_month are deliberately coarse. Together with
age_at_injury they carry the model's date signal without ever forming a
day-resolution date. Do not attempt to supply a finer-grained value.
De-identification requirement
Like every endpoint, the body is scanned for identifiers inbound. Send year and
month as separate integers, never a date string: an ISO date trips the scan and
returns 400 DeIdentificationViolation. Do not add names, record numbers,
claim numbers, or free-text notes to the body. See
conventions.md.
Response
Success — 200 OK
{
"model": "claimcomplexity",
"version": "0.1.0",
"prediction": "high_complexity",
"confidence": 0.6990574472816518,
"probabilities": {
"standard_complexity": 0.30094255271834813,
"high_complexity": 0.6990574472816518
},
"interpretation": "Research proxy for claim procedural complexity; not an official WCB designation."
}
Response fields
| Field | Type | Always present | Description |
|---|---|---|---|
model | string | Yes | The model that answered (claimcomplexity). |
version | string | Yes | The model version that produced this result. Expect it to advance as the model is retrained. |
prediction | string | Yes | The winning label: high_complexity or standard_complexity. |
confidence | number | Yes | Probability of the winning label, 0.0–1.0. Always equals the corresponding entry in probabilities. |
probabilities | object | Yes | Full probability map keyed by label; values sum to ~1.0. |
interpretation | string | Yes | A fixed caveat restating what the label does and does not mean. Surface it wherever you surface the prediction. |
confidence is the model's probability for the winning label, not a measure of
how reliable that probability is. A 0.51 / 0.49 split is a coin flip the
model is reporting honestly — treat narrow margins as "no signal," not as a
weak positive. Read probabilities and apply your own threshold rather than
taking prediction as final.
There is no request_id or timestamp in the success body. To correlate a
successful call, read the X-Request-ID response header: it is the gateway's
trace ID for the request (it does not match an engine request_id), and
support can find the call from it. Error responses
carry both in the envelope.
Status codes
| Code | Meaning | When |
|---|---|---|
200 | OK | Prediction succeeded. |
400 | ValidationError | A feature is missing, the wrong type, outside its documented range, or not an accepted gender / industry_title. |
400 | DeIdentificationViolation | The body contained an identifier shape (e.g. a full date instead of birth_year / accident_month). |
401 | Unauthenticated | Missing or invalid API key. |
402 | PaymentRequired | Insufficient credits or an exhausted budget. See credits.md. |
413 | PayloadTooLarge | Body exceeds the 512 KB limit. |
415 | UnsupportedMediaType | Content-Type is not application/json. |
429 | RateLimited | Per-consumer rate limit exceeded. See Retry-After. |
500 | InternalError | Unexpected server-side failure. Include request_id when reporting. |
502 | UpstreamError | The model service was unreachable or returned an unexpected shape. |
503 | ServiceUnavailable | A required dependency is temporarily unhealthy. |
504 | UpstreamTimeout | The model call exceeded the engine's budget. |
Error envelope
All non-2xx responses use the uniform envelope. Field-level failures name the
offending path in the field extra:
{
"timestamp": "2026-10-14T00:36:46.189Z",
"error": "ValidationError",
"message": "features.accident_month: Input should be less than or equal to 12",
"field": "features.accident_month",
"request_id": "924c7b31-01b2-4f64-b5d6-a1ce666830b6"
}
See errors.md for the full code list.
What a call costs
A prediction is billed at a fixed per-call credit cost — the price does not
vary with input size. The exact credits spent are in the X-Credits-Used
header and the dollar cost in X-Credits-Cost-USD; treat those as the source
of truth for what you were charged. See credits.md.
Validating inputs first with the 1-credit
GET /api/claimcomplexity/options call avoids
paying full price for a request that would only 400.
Examples
curl — success
curl -sS -X POST "https://engine.tripod-health.com/api/claimcomplexity/predict" \
-H "apikey: $ENGINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"features": {
"age_at_injury": 44,
"average_weekly_wage": 900,
"birth_year": 1982,
"accident_month": 4,
"gender": "M",
"industry_title": "Construction"
}
}'
Expected response:
{
"model": "claimcomplexity",
"version": "0.1.0",
"prediction": "high_complexity",
"confidence": 0.6990574472816518,
"probabilities": {
"standard_complexity": 0.30094255271834813,
"high_complexity": 0.6990574472816518
},
"interpretation": "Research proxy for claim procedural complexity; not an official WCB designation."
}
curl — out-of-range value (400)
curl -sS -X POST "https://engine.tripod-health.com/api/claimcomplexity/predict" \
-H "apikey: $ENGINE_API_KEY" \
-H "Content-Type: application/json" \
-w "\nHTTP %{http_code}\n" \
-d '{"features":{"age_at_injury":44,"average_weekly_wage":900,"birth_year":1982,"accident_month":13,"gender":"M","industry_title":"Construction"}}'
Receive (400):
{
"timestamp": "2026-10-14T00:36:46.189Z",
"error": "ValidationError",
"message": "features.accident_month: Input should be less than or equal to 12",
"field": "features.accident_month",
"request_id": "924c7b31-01b2-4f64-b5d6-a1ce666830b6"
}
curl — unknown industry (400)
curl -sS -X POST "https://engine.tripod-health.com/api/claimcomplexity/predict" \
-H "apikey: $ENGINE_API_KEY" \
-H "Content-Type: application/json" \
-w "\nHTTP %{http_code}\n" \
-d '{"features":{"age_at_injury":44,"average_weekly_wage":900,"birth_year":1982,"accident_month":4,"gender":"M","industry_title":"Underwater Basket Weaving"}}'
Receive (400):
{
"timestamp": "2026-10-14T00:59:04.206Z",
"error": "ValidationError",
"message": "unknown industry_title: 'Underwater Basket Weaving'",
"request_id": "ef9ab1fb-0ca2-4efb-b212-80ec355692b6"
}
Note the difference between the two 400s: a shape or range failure carries
field, while an unrecognized category quotes the offending value in the
message instead. Branch on the presence of field, not on message text.
Python (requests)
# Uses the call() helper from quickstart.md.
result = call("POST", "/api/claimcomplexity/predict", body={
"features": {
"age_at_injury": 44,
"average_weekly_wage": 900,
"birth_year": 1982,
"accident_month": 4,
"gender": "M",
"industry_title": "Construction",
},
})
# Apply your own threshold rather than trusting a narrow-margin label.
if result["probabilities"]["high_complexity"] >= 0.75:
escalate(result)
Node.js (native fetch)
// Uses the call() helper from quickstart.md.
const result = await call("POST", "/api/claimcomplexity/predict", {
features: {
age_at_injury: 44,
average_weekly_wage: 900,
birth_year: 1982,
accident_month: 4,
gender: "M",
industry_title: "Construction",
},
});
if (result.probabilities.high_complexity >= 0.75) {
escalate(result);
}
TypeScript
interface ClaimComplexityFeatures {
age_at_injury: number;
average_weekly_wage: number;
birth_year: number;
accident_month: number;
gender: string;
industry_title: string;
}
interface ClaimComplexityPredictResponse {
model: string;
version: string;
prediction: "high_complexity" | "standard_complexity";
confidence: number;
probabilities: Record<string, number>;
interpretation: string;
}
const result = await call<ClaimComplexityPredictResponse>(
"POST",
"/api/claimcomplexity/predict",
{ features: myFeatures satisfies ClaimComplexityFeatures },
);
Intended use
- Triage by administrative burden — surface the claims most likely to generate hearings and IME cycles so they get earlier adjuster attention.
- Bulk scoring of coded claim records where you already hold the six features.
- Threshold-aware routing — read
probabilitiesand apply a threshold that matches your tolerance for false positives, rather than trusting the top label.
Mistaken use
- Do not read this as injury severity or cost. It predicts procedural
friction. For cost category, call
/api/claimcost/classify. - Do not present it as a WCB determination. It is a research proxy trained
on public data. Surface the
interpretationstring alongside the label. - Do not use it to deny, delay, or price a claim. It is a triage signal for allocating human attention, not an adjudication input.
- Do not act on a narrow margin. A
0.52confidence is the model saying it cannot tell. - Do not guess at
industry_title. An unlisted value returns400. Fetch the accepted list from/api/claimcomplexity/options. - Do not send a date of birth or an accident date. Send
birth_yearandaccident_monthas integers. A date string trips the de-identification scan.
Debugging
- Capture the
request_idfrom the error envelope before anything else. A successful call, or a response with no body from the engine, has norequest_id; capture theX-Request-IDresponse header (the gateway's trace ID) instead. 400 ValidationErrorwith afield. A shape or range problem. Thefieldnames the exact path (features.accident_month) and the message names the constraint. Fix that field.400 ValidationErrorwith nofield. The value is not a recognized category. Pull the current list from/api/claimcomplexity/options.400 DeIdentificationViolation. Something identifier-shaped is in the body — most often a full date where a year or month integer belongs.402 PaymentRequired. Out of credits or budget; see credits.md.502/503/504. The model service is unreachable, unhealthy, or slow. Retry with backoff; if it persists, check model-services-health.md and quote therequest_idin a ticket.
Rate limits
Per-consumer limits apply; see rate-limits.md. Responses
include the standard RateLimit-* headers.
Related
- claimcomplexity-options.md — accepted values,
numeric ranges, and the
target_definitionthis model was trained against. Call it first. - claimcost-classify.md — claim cost category from a different feature set. A complementary signal, not a substitute.
- credits.md — fixed-cost billing, the
X-Credits-*headers, and402. - model-services-health.md — check whether the engine's models are healthy.
- conventions.md — de-identification contract, request IDs, timestamps.
- errors.md — error envelope and code list.
Change history
| Date | Change |
|---|---|
| 2026-08-07 | Initial publication (beta). |
| 2026-10-14 | The engine assigns every request ID; an X-Request-ID request header is not used. The X-Request-ID response header is the gateway's trace ID for the request and does not match request_id; quote request_id to support. |