Loading documentation

Access required

Your account doesn't have access to the documentation. Contact your administrator.

Sign out
Skip to main content

API conventions

Status: stable Category: reference Added: 2026-04-20 Last reviewed: 2026-06-03

Summary

Cross-cutting rules that hold across every endpoint in this directory. An integrator who reads this once can skim individual endpoint docs without re-learning the same conventions on each page.

  • Base URL is https://engine.tripod-health.com.
  • JSON only, UTF-8, over HTTPS.
  • Paths are unversioned (no /v1/, no /v2/).
  • Every response carries a request_id for correlation.
  • Timestamps are ISO 8601 UTC with millisecond precision.
  • Success responses have no envelope — the payload is at the top level. Errors use a uniform envelope (see errors.md).
  • Request bodies must be de-identified. Trinity rejects identifiers at the boundary; they do not pass into business logic.

Base URL

Every public endpoint is reached at https://engine.tripod-health.com. HTTP is redirected to HTTPS with a 301. Your client should call the https:// URL directly.

No other hostname belongs in your integration. If you see a different URL in a document or a log line, treat it as an internal detail that is not part of the public contract.

Paths

  • All consumer-facing routes live under /api/. Example: /api/cdri/compute.
  • The one exception is /health, the unauthenticated container liveness probe — not reachable via the public hostname.
  • Paths are not versioned. It is /api/cdri/compute, never /api/v1/cdri/compute. When a contract changes, the catalog's catalog_version changes; the URL does not.
  • Path segments are lowercase. Multi-word resources use snake_case (depression_screen, quick_dash).

HTTP methods

Only GET and POST are in use today. The catalog names which method each endpoint uses — see GET /api/catalog/operations.

MethodUsed for
GETReads that have no side effects: health, version, catalog lookups, /questions listings. Idempotent.
POSTScoring and composite computation: /score, /cdri/compute, /debug/echo. Each call is an independent computation with a persistent audit record.

PUT, PATCH, and DELETE are not used. A request with one of these methods against a known path returns 404 NotFound.

Request format

Headers

Every authenticated request needs:

HeaderRequiredPurpose
apikeyYesConsumer API key. See authentication.md.
Content-TypeOn requests with a bodyMust be application/json. Anything else returns 415 UnsupportedMediaType.
X-Request-IDNoClient-supplied correlation ID (up to 128 characters). If omitted, Trinity generates a UUID.

Body

  • JSON only. No XML, no application/x-www-form-urlencoded, no multipart/form-data.
  • UTF-8.
  • Maximum size 512KB. A larger body returns 413 PayloadTooLarge. No endpoint needs a body anywhere near this ceiling.
  • Field names use snake_case. Example: age_bracket, not ageBracket.

Query parameters

Case-sensitive. Where an endpoint enumerates allowed values (for example ?depth=basic|contextual|full or ?audience=employee|employer|provider), the values are all lowercase and must match exactly.

Response format

Content type

Every response is application/json; charset=utf-8. 401 bodies use a smaller envelope — see authentication.md.

Success shape

No envelope. The payload is at the top level:

{
"score": 72,
"band": "high",
"confidence": { "overall": 0.84, "tier": "high" },
"catalog_version": "0.13.0",
"request_id": "8f2c3b1d-5e4a-4a9c-9b1e-2a7f1d3e4c5b",
"timestamp": "2026-04-20T17:32:10.812Z"
}

Three fields appear on most (not all) successful business responses: catalog_version, request_id, and timestamp. Health and version responses structure those fields differently; see the individual endpoint docs. Purely informational reads such as catalog lookups may omit them when they add no value.

Error shape

Uniform envelope:

{
"timestamp": "2026-04-20T17:32:10.812Z",
"error": "ValidationError",
"message": "Field 'depth' must be one of basic, contextual, full",
"request_id": "...",
"field": "depth"
}

Every non-2xx response Trinity emits follows this shape. See errors.md for the full taxonomy.

Request IDs

Every /api/* response carries a request ID. It is always present in the X-Request-ID response header. It is also echoed in the response body on most endpoints — every error envelope, and every computation response (/score, /cdri/compute, /health/check, /debug/echo). Pure-lookup endpoints such as /catalog/* and /version/get return only the business payload in the body; use the response header there.

Rules:

  • If you send an X-Request-ID request header, up to 128 characters, Trinity uses it verbatim.
  • If you do not, or yours is empty or longer than 128 characters, the Trinity generates a UUID v4.
  • IDs are echoed but not otherwise interpreted. Client-supplied IDs are opaque strings; Trinity does not require UUID format from clients.
  • Every request gets a distinct ID. Do not reuse IDs across calls.

Quote the request ID whenever you contact support about a specific call. It is the fastest path from a symptom to a server-side trace.

Timestamps

All timestamps — in response bodies and in log lines — are ISO 8601 UTC with millisecond precision. Example:

2026-04-20T17:32:10.812Z
  • Always UTC (Z suffix), never a local offset.
  • Always millisecond-resolution (.812).
  • Never a Unix epoch integer in Trinity's public contract.

Parse with any standard ISO 8601 parser:

from datetime import datetime
ts = datetime.fromisoformat("2026-04-20T17:32:10.812Z".replace("Z", "+00:00"))
const ts = new Date("2026-04-20T17:32:10.812Z");

Null vs. missing

When a field is documented as "always present," it is present on every response — explicit null when the value is unknown, never omitted. When a field is documented as optional, it may be omitted entirely from the response.

Example — a composite that could not classify a phenotype:

{
"cdri_score": 68,
"phenotype": null,
"confidence": { "overall": 0.54, "tier": "medium" }
}

phenotype: null is correct; phenotype being absent from the response entirely is a bug worth reporting.

Client-side defensive reading: for an always-present field, read it directly and handle null explicitly. Do not test for presence on fields the doc says are always present.

De-identification boundary

Trinity is a de-identification contract. Request bodies are scanned on the way in; anything that looks like an identifier is rejected with 400 DeIdentificationViolation before business logic runs.

What Trinity rejects

CategoryExamples
Blocked field names (any depth in the body)name, first_name, last_name, full_name, ssn, dob, date_of_birth, email, phone, mrn, patient_id, member_id
Value patternsSSN shape (\d{3}-\d{2}-\d{4}), email shape, phone-number shape, precise past-dated ISO date of birth

The first hit wins. Trinity returns field naming the offending path; the value itself is never echoed.

The one date exception: onset / as_of

The acuity inputs onset and (optionally) as_of — accepted by /api/acuity/compute and by /api/cdri/compute when you request the embedded acuity view — are the only fields allowed to carry a date. The engine converts them into a duration (weeks-since-onset) at the request boundary and discards the raw date: it is never persisted or logged. A duration is not a Safe Harbor identifier; a date is. A date-shaped value anywhere other than onset/as_of is still rejected.

What to send instead

Identifier you'd naively sendSend this instead
Date of birthdemographics.age_bracket (for example "35-44")
Legal nameNothing — Trinity doesn't need a name to produce a score
SSN or MRNNothing — Trinity does not correlate across calls by subject
Email / phoneNothing — see above
Street addressdemographics.region (state/region granularity)
NAICS code + job titledemographics.occupation_class

If your workflow requires correlating multiple calls back to one subject, generate an opaque token on your side, pass it through whatever channel your pipeline uses, and re-associate it after the request. Trinity never sees the subject identity.

URL patterns

  • One resource per path segment. No query-string-only endpoints.
  • Verb-like paths at the tail (/questions, /score, /compute, /check, /get) clarify the operation even when the HTTP method alone would.
  • No trailing slashes. /api/catalog/get is canonical; /api/catalog/get/ returns 404.

Idempotency

  • GET calls are idempotent and safe to retry on any retriable failure status.
  • POST calls (/score, /cdri/compute) are computationally repeatable but not idempotent — each call is treated as a new request server-side. Retrying a 5xx on POST is correct behavior. There is no client-supplied idempotency key today.

Request size guidance

  • A /score body for the longest instrument in the catalog is a few hundred bytes.
  • A /cdri/compute body carrying every instrument's responses and demographics is typically well under 10 KB.
  • If your request approaches 100 KB, review what you are sending — no endpoint requires bodies that large, and you may be accidentally including free-form content that will trip the de-identification filter.

Change history

DateChange
2026-04-20Initial publication.
2026-06-03Removed the tpa audience value; documented the onset/as_of date exception for the acuity surface.