Errors
Every error response uses a consistent envelope. Switch on the machine-readable error.code rather than parsing the message.
Standard error shape
{
"error": {
"code": "unauthorized",
"message": "Invalid access token",
"details": [],
"request_id": "6a5d5b2d-2cf0-4b7f-a9e3-7f2c66d4c4c9"
}
}The details array is always present on the error envelope. It is an empty [] when no per-field context applies (e.g. 401 unauthorized, 404 not_found, 500 internal_error). When the failure is validation-related or spans multiple fields, each entry has the shape:
{
"field": "weight_unit",
"code": "invalid_value",
"message": "Unknown unit. Accepted values: kg, lb."
}field: dotted path into the request body or the name of the offending query/header parameter.code: machine-readable failure reason (required,invalid_value,too_long, etc.).message: human-readable explanation.
The top-level error.code and error.message always describe the request as a whole; entries in details[] are the specific causes.
HTTP status codes
| Status | Meaning | When it happens |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
202 | Accepted | Async operation started (e.g. lab processing, backfill) |
204 | No Content | Update or delete succeeded; no body returned |
304 | Not Modified | Cached copy is still good |
400 | Bad Request | Invalid request body, missing required fields, malformed JSON |
401 | Unauthorized | Missing, expired, or invalid token |
403 | Forbidden | Valid token but insufficient permissions |
404 | Not Found | Resource does not exist |
405 | Method Not Allowed | HTTP method not supported for the endpoint |
409 | Conflict | Resource already exists or state conflict |
413 | Payload Too Large | Request body or upload exceeds size limits |
415 | Unsupported Media Type | Unsupported content-type |
422 | Unprocessable Entity | Request is well-formed but semantically invalid |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server failure |
502 | Bad Gateway | Upstream dependency failure |
503 | Service Unavailable | Temporary outage or maintenance |
Error codes
The error.code field provides machine-readable error classification. Switch on this field rather than parsing the message.
| Code | HTTP status | Description |
|---|---|---|
invalid_request | 400 | Request body is malformed or missing required fields |
unauthorized | 401 | Token is missing, expired, or invalid |
forbidden | 403 | Token is valid but does not have access to this resource |
not_found | 404 | The requested resource does not exist |
conflict | 409 | Resource already exists or state conflict |
validation_error | 422 | Request is well-formed but contains invalid values |
rate_limited | 429 | Rate limit exceeded; retry after the indicated period |
internal_error | 500 | Unexpected server error |
provider_error | 502 | Upstream provider returned an error |
service_unavailable | 503 | The service is temporarily unavailable. Respect the Retry-After header. |
Error examples
Error handling best practices
- On
401, request a new token from your backend, then retry. - On
429, respect theRetry-Afterheader; do not retry immediately. - On
502/503, retry with exponential backoff (recommended: 1s, 2s, 4s, 8s, max 3 retries). - On
409, the resource already exists; read the current state instead of retrying the create. - On
422, check the message for which field/value is invalid; this is a client-side fix.
Rate & token limits
Thrive AI Health enforces per-tenant request rate limits on every endpoint and per-tenant token quotas on endpoints that invoke LLMs (coaching chat, nudge generation, lab and workout analysis, insights). Both are tracked on the tenant; there is no separate user-level quota.
Concrete request and token limits are assigned per tenant during partner onboarding and communicated out-of-band. Read the RateLimit-* and TokenLimit-* response headers on every call to track remaining quota in-band.
# Quota remaining
RateLimit-Limit: 600
RateLimit-Remaining: 598
RateLimit-Reset: 1710601800
# Token quota remaining
TokenLimit-Limit: 60000
TokenLimit-Remaining: 59800
TokenLimit-Reset: 1710601800
# Overages return a Retry-After header
Retry-After: 12On overage, the response body's error.type field is requests or tokens, indicating which quota was exhausted:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Retry after 12 seconds.",
"type": "requests"
}
}Base URL and format
Environments, authentication headers, JSON conventions, pagination, dates, and other wire-level details that apply to every endpoint.
Event stream
Thrive AI Health publishes asynchronous events (lab results, daily device data, coaching nudges) to partner-configured message queues. This page covers the delivery model, signature verification, and event catalog.