Claim-Cost Classification
Status:
betaCategory:claimcostAdded:2026-07-06Last reviewed:2026-07-06
Summary
Classify the likely cost of a workers' compensation claim from three
de-identified inputs — the injury, the body part, and the worker's age. One
call returns two independent classifications: a binary cost tier
(High / Low) and a three-band cost band (High / Medium / Low).
Each carries a confidence and the full probability distribution, so you can
apply your own threshold instead of taking the top label as final.
This is a statistical model, not clinical or actuarial advice. It does not set a reserve, price a policy, or make a claim decision — it estimates a cost category from a narrow feature set. Treat the output as one signal among many.
Endpoint
| Field | Value |
|---|---|
| Method | POST |
| Path | /api/claimcost/classify |
| Full URL | https://engine.tripod-health.com/api/claimcost/classify |
| 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 when you have a coded injury, a coded body part, and an age, and you want a fast cost-category read. It is built to triage or prioritize — to separate the claims likely to run expensive from the ones likely to stay cheap — not to produce a dollar figure.
The two valid input vocabularies are fixed and case-sensitive at the word
level. Fetch them from
GET /api/claimcost/categories and validate or
populate your inputs 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. |
X-Request-ID | No | Optional client-generated correlation ID. If omitted, one is generated and echoed in the X-Request-ID response header. |
Path parameters
None.
Query parameters
None.
Body
{
"injury": "strain or tear",
"bodyPart": "low back area",
"age": 47
}
Body fields
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
injury | string | Yes | non-empty, ≤ 200 chars, must match a known category | The injury cause/nature. Case-insensitive, but the words must match one of the accepted injuries values verbatim. |
bodyPart | string | Yes | non-empty, ≤ 200 chars, must match a known category | The affected body part. Case-insensitive, but the words must match one of the accepted bodyParts values verbatim. Maps to the model's body_part. |
age | integer | Yes | 0 ≤ age ≤ 120 | The worker's age as a whole number of years. |
Category matching is exact after case-folding and trimming: "low back area",
"Low Back Area", and "LOW BACK AREA" are equivalent, but "lower back" is
not a known value and returns 400. Unknown top-level fields are ignored.
De-identification requirement
Like every endpoint, the body is scanned for identifiers inbound. age must
be a whole number of years — never a date of birth. A date-shaped value is
both wrong for the model and an identifier shape that returns
400 DeIdentificationViolation. Do not add names, dates, record numbers, or
free-text notes to the body. See
conventions.md.
Response
Success — 200 OK
{
"model": "claimcost",
"version": "0.2.0",
"costTier": {
"prediction": "High",
"confidence": 0.82,
"probabilities": {
"High": 0.82,
"Low": 0.18
}
},
"costBand": {
"prediction": "Medium",
"confidence": 0.54,
"probabilities": {
"High": 0.3,
"Medium": 0.54,
"Low": 0.16
}
}
}
Response fields
| Field | Type | Always present | Description |
|---|---|---|---|
model | string | Yes | The model that answered (claimcost). |
version | string | Yes | The model version that produced this result. Reported by the model; expect it to advance as the model is retrained. |
costTier | object | Yes | The binary cost classification (High / Low). |
costTier.prediction | string | Yes | The winning label: High or Low. |
costTier.confidence | number | Yes | Probability of the winning label, 0.0–1.0. |
costTier.probabilities | object | Yes | Full probability map keyed by label (High, Low); values sum to ~1.0. |
costBand | object | Yes | The three-band cost classification (High / Medium / Low). |
costBand.prediction | string | Yes | The winning label: High, Medium, or Low. |
costBand.confidence | number | Yes | Probability of the winning label, 0.0–1.0. |
costBand.probabilities | object | Yes | Full probability map keyed by label (High, Medium, Low); values sum to ~1.0. |
costTier and costBand are independent classifications from the same inputs,
not two views of one score. They can disagree (a Low tier with a Medium
band is possible); use whichever granularity fits your use, or both.
There is no request_id or timestamp in the success body; read the
X-Request-ID response header to correlate a successful call. Error responses
carry both in the envelope.
Status codes
| Code | Meaning | When |
|---|---|---|
200 | OK | Classification succeeded. |
400 | ValidationError | Missing or empty injury / bodyPart, a value over 200 characters, a non-integer or out-of-range age, or an unrecognized injury / bodyPart category. The field extra names the offender for field-shape errors; an unknown-category message quotes the offending value. |
400 | DeIdentificationViolation | The body contained an identifier shape (e.g. a date supplied for age). |
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:
{
"timestamp": "2026-07-06T17:32:10.812Z",
"error": "ValidationError",
"message": "Field 'age' must be between 0 and 120",
"request_id": "8f2c3b1d-5e4a-4a9c-9b1e-2a7f1d3e4c5b",
"field": "age"
}
See errors.md for the full code list.
What a call costs
A successful classification is billed at a fixed per-call credit cost.
Unlike /api/ask/run, the price does not vary with input
size — this is a fixed-cost route like the analytics endpoints. The exact
credits a call spent are returned 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 for the credit model
and where to find current per-route costs.
Validating inputs first with the cheap
GET /api/claimcost/categories call avoids paying
for a classify request that would only 400 on an unknown category.
Examples
curl — success
curl -sS -X POST "https://engine.tripod-health.com/api/claimcost/classify" \
-H "apikey: $ENGINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"injury":"strain or tear","bodyPart":"low back area","age":47}'
Expected response:
{
"model": "claimcost",
"version": "0.2.0",
"costTier": {
"prediction": "High",
"confidence": 0.82,
"probabilities": { "High": 0.82, "Low": 0.18 }
},
"costBand": {
"prediction": "Medium",
"confidence": 0.54,
"probabilities": { "High": 0.3, "Medium": 0.54, "Low": 0.16 }
}
}
curl — unknown category (400)
curl -sS -X POST "https://engine.tripod-health.com/api/claimcost/classify" \
-H "apikey: $ENGINE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Request-ID: docs-claimcost-unknown-injury" \
-w "\nHTTP %{http_code}\n" \
-d '{"injury":"lower back","bodyPart":"low back area","age":47}'
Receive (400):
{
"timestamp": "2026-07-06T17:32:10.812Z",
"error": "ValidationError",
"message": "unknown injury: 'LOWER BACK'",
"request_id": "docs-claimcost-unknown-injury"
}
Python (requests)
# Uses the call() helper from quickstart.md.
result = call("POST", "/api/claimcost/classify", body={
"injury": "strain or tear",
"bodyPart": "low back area",
"age": 47,
})
print(result["costTier"]["prediction"], result["costTier"]["confidence"])
print(result["costBand"]["prediction"], result["costBand"]["confidence"])
Node.js (native fetch)
// Uses the call() helper from quickstart.md.
const result = await call("POST", "/api/claimcost/classify", {
injury: "strain or tear",
bodyPart: "low back area",
age: 47,
});
console.log(result.costTier.prediction, result.costTier.confidence);
console.log(result.costBand.prediction, result.costBand.confidence);
TypeScript
interface CostClass {
prediction: string;
confidence: number;
probabilities: Record<string, number>;
}
interface ClaimcostClassifyResponse {
model: string;
version: string;
costTier: CostClass;
costBand: CostClass;
}
const result = await call<ClaimcostClassifyResponse>(
"POST",
"/api/claimcost/classify",
{ injury: "strain or tear", bodyPart: "low back area", age: 47 },
);
Intended use
- Triage and prioritization — flag the claims most likely to run expensive so they get earlier attention.
- Bulk scoring of coded injury records where you already hold a known injury cause, body part, and age.
- Confidence-aware routing — read
probabilitiesand apply your own threshold rather than trusting a narrow-margin top label.
Mistaken use
- Do not treat the output as a dollar amount or a reserve. It is a cost category, not a figure. Setting a reserve is a human, actuarial decision.
- Do not guess at category strings. An unlisted value returns
400. Fetch the accepted values from/api/claimcost/categoriesand match against them. - Do not send a date of birth in
age. Send a whole number of years. A date trips the de-identification scan (400). - Do not use this for free-text questions about a claim. That is
/api/ask/run. This endpoint takes a fixed feature set and returns fixed labels.
Debugging
- Capture the
request_idfrom the error envelope or theX-Request-IDresponse header before anything else. 400 ValidationErrorwith afield. A field-shape problem —injury/bodyPartmissing, empty, or too long, oragenot a whole number in0–120. Fix the named field.400 ValidationErrorwith nofield, messageunknown injury:/unknown body_part:. The value is not a recognized category. Pull the current list from/api/claimcost/categories.400 DeIdentificationViolation. Something identifier-shaped is in the body — most often a date passed forage. Send an integer.402 PaymentRequired. Out of credits or budget; see credits.md.502 UpstreamError. The model service is unreachable or returned an unexpected shape. Retry with backoff; if it persists, check model-services-health.md and quote therequest_idin a ticket.
Rate limits
Per-consumer limits are enforced at the gateway; see
rate-limits.md. Responses include the standard
RateLimit-* headers.
Related
- claimcost-categories.md — the accepted
injuryandbodyPartvalues. Call it first to validate inputs. - 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-07-06 | Initial publication (beta). |