Partner API v1.0
Partner Documentation

Build with Healify

Anna, our AI health coach, plus nutrition tracking, bloodwork analysis, DNA insights, and 150+ health metrics — all via a single REST API.

Production: ai.healify.ai REST + SSE streaming JWT Bearer Auth 472 endpoints

Authentication

JWT Bearer Token

All endpoints require a JWT in the Authorization header. Obtain a token via Apple Sign In or email auth. Tokens expire — use the refresh token to renew.

Header
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

Base URLs

PROD https://ai.healify.ai

DEV https://ai-dev.healify.ai

All endpoints are prefixed with /api. The dev environment is a full mirror of production — use it for integration testing.

Chat (Anna AI)

10 endpoints
POST /api/chat/confirm Confirm a pending destructive tool call

Exchange a pending_confirmation nonce (issued by chat_agent when a destructive tool was first invoked) for a confirmed result. Used by the LangGraph chat_agent to complete destructive operations after explicit user consent in the mobile app.

POST /api/chat/feedback Submit thumbs up/down feedback for a chat response

Tracks user feedback on AI responses. Links to LangWatch traces via run_id for quality monitoring.

FieldTypeRequiredDescription
message_idstringrequiredMessage ID the feedback is for
thread_idstringoptionalThread ID of the conversation
ratingstringrequiredThumbs up or down
run_idstringoptionalLangGraph run ID for trace linking
commentstringoptionalOptional user comment about the response
POST /api/chat/graph Send message to unified AI agent system

Automatically routes to appropriate agent (chat, nutrition, goal, habit, metrics) based on message content.

FieldTypeRequiredDescription
streamingstringrequired (in query)
messagestringrequiredThe message content
typestringoptionalMessage type
optionsobjectoptional
user_idnumberoptionalOptional user ID for testing/debugging (should not be used in production)
agentTypestringoptionalOptional agent type to route the message to a specific agent
languagestringoptionalOverride response language (e.g. "spanish"). Falls back to user profile language.
is_thread_endbooleanoptionalSignal that this is the last message in the session (e.g. user backgrounds app or closes chat). When true, LangWatch quality evaluators fire for this conversation turn.
threadIdstringoptionalLangGraph thread ID for conversation continuity. Sent by the mobile client when resuming an existing thread.
posthog_session_idstringoptionalPostHog session recording ID for LLM trace session-replay linking
pillarsstring[]optionalExplicit pillar hints forwarded to Anna for deterministic routing. When set, Anna bypasses rule-based pillar classification and scopes tools/prompts to the listed pillars.
GET /api/chat/history Get chat history

Retrieve paginated chat history for the current user. Returns messages in reverse chronological order.

FieldTypeRequiredDescription
limitnumberrequired (in query)
POST /api/chat/reset Reset the user's current chat session

Clears User.threadId so the next chat message starts a fresh AgentCore session. Call this when the client wants to force a new conversation (e.g. "New chat" button).

GET /api/chat/sources Get source citations for chat message

Retrieve credible health sources for Anna's responses (App Store compliance). Returns 202 Accepted if sources are being generated in the background.

FieldTypeRequiredDescription
threadIdstringrequired (in query)
POST /api/chat/threads Create a new chat thread

Creates a new conversation thread for the user.

GET /api/chat/threads List chat thread summaries

Retrieve paginated list of chat threads with their last message.

FieldTypeRequiredDescription
limitnumberrequired (in query)
beforestringrequired (in query)
GET /api/chat/threads/{threadId}/messages Get messages for a specific thread

Retrieve messages for a specific conversation thread.

FieldTypeRequiredDescription
threadIdstringrequired
limitnumberrequired (in query)
beforestringrequired (in query)
POST /api/chat/warm Pre-warm Anna session for near-instant first response

Sends a warm sentinel to AgentCore with the real runtimeSessionId so the first real chat message skips the cold-start tax. Call on app open / login / chat-screen mount. Returns the threadId to use for the next send.

Nutrition

13 endpoints
POST /api/nutrition/analyze-food-key Analyze a food photo already uploaded to S3

Analyzes a food photo that was previously uploaded to S3 using a presigned URL from GET /nutrition/upload-url. Use this after the client has uploaded directly to S3. Provide the S3 object key, optional text context, and meal type hint for better accuracy.

FieldTypeRequiredDescription
keystringoptionalS3 object key of the uploaded food photo
messagestringoptionalOptional text context
mealTypestringoptionalMeal type hint
POST /api/nutrition/analyze-food-photo Analyze a food photo using AI vision

Upload a food photo for AI-powered nutritional analysis. Use when the user takes a photo of their meal and wants to know calories, macros, and food identification. Accepts multipart/form-data with a photo file up to 10MB. Returns identified foods with estimated nutritional breakdown.

FieldTypeRequiredDescription
messagestringoptionalOptional text context for the food photo
mealTypestringoptionalMeal type hint
POST /api/nutrition/analyze-food-text Estimate nutrition for a typed food name (text search)

Returns ranked candidate foods with per-serving nutrition for a food name or short description the user typed. Use to back a "search food by name" box — pick a candidate and log it via POST /nutrition/food. Read-only: no image, no S3, no DB write.

FieldTypeRequiredDescription
querystringrequiredFood name or short description typed by the user
mealTypestringoptionalMeal type hint
POST /api/nutrition/food Log food intake entry

Records a food intake entry with nutritional data for the authenticated user. Use when the user reports eating a meal or snack and wants to track calories and macros. Provide food name, calories, and optionally protein, carbs, fat, and meal type.

FieldTypeRequiredDescription
imageUrlstringoptional
descriptionstringoptional
caloriesnumberrequired
proteinnumberrequired
carbsnumberrequired
fatnumberrequired
fibernumberoptional
itemsstring[]optional
mealTypestringoptional
foodSourcestringoptional
healthScorenumberoptional
confidencestringoptional
userEditedbooleanoptional
GET /api/nutrition/food/today Get today's food log entries

Returns all food log entries for today with nutritional breakdown per entry and daily totals. Use when the user asks what they've eaten today, wants to check remaining calories, or needs a nutrition summary for the day.

DELETE /api/nutrition/food/{id} Delete a food log entry (owner-scoped)

Permanently removes the user's own food log entry by ID. Owner-scoped: only the owning user may delete. Returns the deleted entry's id.

FieldTypeRequiredDescription
idnumberrequired
POST /api/nutrition/meal-plan Generate personalized meal plan via nutrition service

Creates a customized meal plan based on caloric needs, dietary preferences, and duration. Use when the user asks for a new meal plan from the nutrition module. For the dedicated meal plan service with queue-based generation, use the /mealplan endpoints instead. Requires an active subscription or available free-tier usage.

FieldTypeRequiredDescription
caloriesnumberrequiredTarget daily calories
dietTypestringrequiredDiet type preference
numberOfDaysnumberrequiredNumber of days to generate meal plan for
GET /api/nutrition/streak Get user nutrition tracking streak

Returns the current streak count for the specified tracking type (defaults to meal_logging). Use when the user asks about their logging streak or for gamification features showing consistency.

FieldTypeRequiredDescription
typestringoptionalStreak type (default: meal_logging) (in query)
GET /api/nutrition/today Get today's nutrition summary (V2)

Returns today's calorie intake, macro breakdown (protein/carbs/fat with goals), and a list of logged meals. Use when the user asks what they've eaten today, how many calories they've consumed, or wants to see their macro progress. Returns hasData: false with zero values when no food has been logged today — never interpret zeroes as dietary truth without checking hasData.

GET /api/nutrition/upload-url Get presigned S3 URL for direct food photo upload

Generates a presigned S3 PUT URL for the client to upload a food photo directly to S3 without routing through the API. Use before calling analyze-food-key when the client prefers direct S3 upload over multipart form upload. Returns the presigned URL and the S3 key to use with analyze-food-key.

POST /api/nutrition/water Log water intake entry

Records a water intake entry for the authenticated user. Use when the user reports drinking water or wants to track hydration. Accepts amount in milliliters.

FieldTypeRequiredDescription
amountMlnumberrequiredAmount of water in milliliters
loggedAtstringoptionalWhen the water was consumed
GET /api/nutrition/water/today Get today's water intake summary

Returns the total water intake for today with individual entries and progress toward the daily goal. Use when the user asks how much water they've had today or wants to check hydration status.

DELETE /api/nutrition/water/{id} Delete a water log entry (owner-scoped)

Permanently removes the user's own water log entry by ID. Owner-scoped: only the owning user may delete. Returns the deleted entry's id.

FieldTypeRequiredDescription
idnumberrequired

Health Data

11 endpoints
POST /api/health/bloodwork/analyze Analyze bloodwork results

Provides comprehensive AI-powered analysis of bloodwork results with personalized recommendations and risk assessment. Use when the user uploads or asks about their blood test results (CBC, metabolic panel, lipid panel, thyroid, etc.). Returns detailed marker analysis, out-of-range flags, and health recommendations.

FieldTypeRequiredDescription
glucosenumberrequiredBlood glucose level in mg/dL
cholesterolnumberrequiredTotal cholesterol in mg/dL
hemoglobinnumberrequiredHemoglobin in g/dL
testDatestringrequiredTest date
hdlnumberoptionalHDL cholesterol in mg/dL
ldlnumberoptionalLDL cholesterol in mg/dL
triglyceridesnumberoptionalTriglycerides in mg/dL
POST /api/health/comprehensive Process comprehensive health data (150+ HealthKit metrics)

Unified endpoint for processing all HealthKit metrics with AI-powered analysis, anomaly detection, and personalized insights. Use when receiving a full health data sync from the mobile app with multiple metric types (steps, heart rate, HRV, sleep, blood oxygen, weight, BMI, and 140+ more). Returns processed results with anomaly flags and insights.

FieldTypeRequiredDescription
metricsobject[]requiredArray of health metrics (supports 150+ HealthKit metrics)
syncedAtstringoptionalSync timestamp
deviceInfoobjectoptionalClient device info
skipAggregationbooleanoptionalSkip post-sync aggregation and scoring (use for historical backfill where latency matters). When true, processedCount is populated but healthScore/insights/anomalies are omitted.
POST /api/health/emergency-alert Process emergency health alert

Handle real-time emergency health notifications with automatic escalation and emergency service coordination. Use when a critical health event is detected (e.g., fall detection, abnormal heart rhythm, dangerously low blood oxygen). Triggers escalation workflows and returns actions taken.

FieldTypeRequiredDescription
alertTypestringrequired
severitystringrequired
triggerMetricstringrequiredMetric that triggered the alert
triggerValuenumberrequiredValue that triggered the alert
thresholdValuenumberrequiredThreshold value that was exceeded
locationobjectoptionalUser location data for emergency services
contextobjectoptionalAdditional context data
DELETE /api/health/healthkit/batch-delete Batch delete HealthKit data by Apple sample UUIDs

Batch delete HealthKit data by Apple sample UUIDs. Removes data at health / healthkit / batch-delete. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
uuidsstring[]requiredArray of HealthKit sample UUIDs to delete. These are the Apple-assigned UUIDs stored in metadata.hkSampleUuid during bulk sync.
POST /api/health/healthkit/bulk-sync Bulk sync comprehensive HealthKit data with unit normalization

Bulk sync comprehensive HealthKit data with unit normalization. Accepts and processes data at health / healthkit / bulk-sync. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
healthDataobject[]requiredArray of health data points (max 5000 per request — chunk larger syncs)
isBackgroundSyncbooleanoptionalBackground sync flag for historical data
batchIdstringoptionalSync batch identifier
totalBatchesnumberoptionalTotal expected batches for this sync session
batchNumbernumberoptionalCurrent batch number
workoutsobject[]optionalNative HKWorkout samples. Persisted to HealthkitWorkout for workout cohesion (activity type, events, routes, swim strokes). Orthogonal to healthData — decomposed quantity samples from the same workout still flow through healthData[] for backwards compat.
GET /api/health/healthkit/sync-coverage Get HealthKit sync coverage

Returns oldest/newest dates, row count, and distinct metric count for this user.

GET /api/health/insights Get personalised health insights and home briefing (V2)

Returns a home briefing sentence, per-domain health insights (fitness, sleep, nutrition, mental, heart, bloodwork) with status levels and scores, and the overall health score. Use when the user opens the Home screen, asks "how is my health?", or wants a summary of their health state. Check overallScoreAvailable before interpreting overallScore: when false, overallScore is 0 (hasData false) or null (metric not ready) — not a poor health score. hasData: false means the user has not yet synced Apple Health data — do not interpret overallScore: 0 as a poor health score in that case. Insights are derived from the user's scored focuses and the latest AI-computed health metric. computedAt is the ISO-8601 timestamp of the snapshot — use it to inform the user if data is stale.

POST /api/health/insights/{profile} Generate profile-specific health insights

Create personalized health insights and recommendations based on comprehensive data analysis for a specific health profile category. Use when the user wants detailed analysis of a particular health domain (e.g., cardiovascular, sleep, nutrition). Returns AI-generated insights with confidence scores and actionable recommendations.

FieldTypeRequiredDescription
profilestringrequiredHealth profile category to analyze
POST /api/health/predictive-analysis Generate predictive health analysis

Create AI-powered predictions for health metrics based on historical data, lifestyle patterns, and risk factors. Use when the user asks about future health trends, projected outcomes, or wants to understand where their health is heading. Returns predictions with confidence intervals and contributing factors.

FieldTypeRequiredDescription
targetMetricstringrequiredMetric to predict
timeHorizonDaysnumberrequiredPrediction time horizon in days
targetDatestringoptionalSpecific date to predict for
includeRiskFactorsbooleanoptionalInclude risk factors analysis
includeRecommendationsbooleanoptionalInclude preventative recommendations
POST /api/health/sync Sync health data from HealthKit

Receives and stores health data synced from the mobile HealthKit integration. Use when the user has new health data to upload from their device. This is the legacy sync endpoint; prefer POST /health/comprehensive for new integrations.

FieldTypeRequiredDescription
stepsnumberrequiredNumber of steps taken
heartRatenumberrequiredHeart rate in beats per minute
caloriesnumberrequiredCalories burned
sleepHoursnumberrequiredSleep duration in hours
datestringrequiredDate of the health data
GET /api/health/validated-types Get supported HealthKit metric types with Apple identifiers

Returns the list of promoted HealthKit types including their Apple identifiers, categories, display names, and units. Use when the user asks what health metrics are tracked or available. Helpful for understanding which data types can be synced from wearables.

Health Profile

3 endpoints
GET /api/health-profile Get unified health profile for the current user

Returns the full Unified Health Profile (health score, data completeness, source breakdown, AI correlations) for the authenticated user. This is the starting point for personalized health advice. Use when you need a comprehensive view of the user's health status before giving recommendations. Returns null if the profile has not yet been computed.

GET /api/health-profile/summary Get health profile summary for dashboard cards

Returns a lightweight summary (health score, data completeness percentage, last sync timestamp) suitable for dashboard cards and overview screens. Use this instead of the full profile when you only need high-level health status. Returns an empty object ({}) when no profile exists.

GET /api/health-profile/trends Get time-series trend data for health metrics

Returns time-bucketed metric trend data for charting and visualization. Supports querying one or multiple metrics (comma-separated). Use when the user asks about health trends over time, wants to see charts, or asks "how has my heart rate been this week?". Returns data points suitable for line/bar charts.

FieldTypeRequiredDescription
userIdnumberoptionalTarget user ID. Defaults to current authenticated user. (in query)
metricTypestringoptionalMetric type, or comma-separated metric types (in query)
startDatestringoptionalStart date (ISO-8601) (in query)
endDatestringoptionalEnd date (ISO-8601) (in query)
resolutionstringoptionalBucket resolution override. If omitted or auto, resolution is chosen by date range. (in query)

Metrics

7 endpoints
POST /api/metrics Submit daily health metrics (single or batch)

Accepts either single-day metrics (date + metrics object) or batch metrics (dailyMetrics array). Use when syncing daily health data from the mobile app. Supports backward compatibility with the single-day format. Triggers health score calculation and AI analysis.

FieldTypeRequiredDescription
datestringoptional
metricsobject[]optional
healthScorenumberoptional
dailyMetricsobject[]optional
POST /api/metrics/fill-with-chat Fill missing metrics via AI chat conversation

Uses AI chat to interactively fill in missing health metrics for the specified focus area. Use when the user has incomplete data and wants AI assistance to estimate or gather missing values through conversation.

GET /api/metrics/health-score/history Get health score history time-series for the authenticated user

Returns health score data points over a time period (7d, 30d, or 90d). Each entry includes the date, score, and optional pillar breakdown. Triggers backfill for rows with missing scores if insufficient data points exist. Not Anna-facing (x-anna-expose: false).

FieldTypeRequiredDescription
periodstringoptionalTime period for score history. Defaults to 7d. (in query)
POST /api/metrics/health-score/recalculate Recalculate health score from latest metrics

Re-runs AI analysis on the latest daily metric, rebuilds the rolling health summary, and updates the user record. Use when the user explicitly requests a health score refresh or after significant data updates. This is a heavier operation than normal metric submission.

POST /api/metrics/recommendations Generate AI health recommendations from metrics

Generates personalized health recommendations based on the provided daily metrics data. Use when the user asks for advice or recommendations after submitting health data. Returns AI-generated suggestions for improving health outcomes.

FieldTypeRequiredDescription
metricsobject[]required
datestringrequired
healthScorenumberoptionalPre-computed health score from mobile
dailyMetricsobjectoptionalBatch format only; ignored for single-day validation when present alongside date/metrics.
GET /api/metrics/survey Get health survey responses for the user

Returns the user's most recent health survey answers (sleep quality, stress, diet, exercise self-assessments). Use when you need subjective health data that complements objective HealthKit metrics. Returns empty object for new users who have not completed a survey.

POST /api/metrics/survey Submit health survey answers and compute initial metrics

Processes user health survey answers (self-reported sleep, stress, diet, exercise ratings) and computes initial health metrics and scores. Use during onboarding or when the user completes a periodic health assessment survey.

Bloodwork

10 endpoints

Upload, parse, and explain blood-test reports. To order new panels through an integrated lab and have results flow back here automatically, see Lab Partners.

POST /api/bloodwork/confirm-upload Confirm presigned bloodwork upload and start analysis

Call after the client PUTs the file to the presigned URL. The key must match the authenticated user.

FieldTypeRequiredDescription
keystringrequiredS3 object key returned from presign (must be under bloodwork/<userId>/…)
mimetypestringrequired
GET /api/bloodwork/explain/{bloodReportId} Explain bloodwork

Explain bloodwork. Returns data at bloodwork / explain / :bloodReportId. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
bloodReportIdnumberrequired
messagestringrequiredThe message content
typestringoptionalMessage type
optionsobjectoptional
user_idnumberoptionalOptional user ID for testing/debugging (should not be used in production)
agentTypestringoptionalOptional agent type to route the message to a specific agent
languagestringoptionalOverride response language (e.g. "spanish"). Falls back to user profile language.
is_thread_endbooleanoptionalSignal that this is the last message in the session (e.g. user backgrounds app or closes chat). When true, LangWatch quality evaluators fire for this conversation turn.
threadIdstringoptionalLangGraph thread ID for conversation continuity. Sent by the mobile client when resuming an existing thread.
posthog_session_idstringoptionalPostHog session recording ID for LLM trace session-replay linking
pillarsstring[]optionalExplicit pillar hints forwarded to Anna for deterministic routing. When set, Anna bypasses rule-based pillar classification and scopes tools/prompts to the listed pillars.
POST /api/bloodwork/from-text Save a blood report parsed from free text in chat

Save a blood report parsed from free text in chat. Accepts and processes data at bloodwork / from-text. Authenticated endpoint — honours the caller's JWT for per-user scope.

GET /api/bloodwork/list Get bloodwork list

Get bloodwork list. Returns data at bloodwork / list. Authenticated endpoint — honours the caller's JWT for per-user scope.

POST /api/bloodwork/presign-upload Presign direct S3 upload for bloodwork

Step 1 of 2: Returns a presigned S3 URL for direct bloodwork file upload. After uploading the file via PUT to the returned URL, call POST /bloodwork/confirm-upload with the returned key to finalize. Requires JWT authentication.

FieldTypeRequiredDescription
fileNamestringrequired
contentTypestringrequired
fileSizenumberrequiredDeclared file size in bytes (for client validation)
POST /api/bloodwork/upload Upload and analyze bloodwork files (sync)

Upload and analyze bloodwork files (sync). Accepts and processes data at bloodwork / upload. Authenticated endpoint — honours the caller's JWT for per-user scope.

POST /api/bloodwork/upload-async Create bloodwork upload-async

Create bloodwork upload-async. Accepts and processes data at bloodwork / upload-async. Authenticated endpoint — honours the caller's JWT for per-user scope.

GET /api/bloodwork/{id} Get bloodwork

Get bloodwork. Returns data at bloodwork / :id. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
DELETE /api/bloodwork/{id} Delete a bloodwork report

Permanently deletes a bloodwork report owned by the authenticated user. Irreversible. Returns 404 when the report does not exist and 403 when it belongs to a different user. Destructive op — requires a confirmation_token from the MCP/app confirmation flow.

FieldTypeRequiredDescription
idnumberrequired
GET /api/bloodwork/{id}/marker/{markerName} Get bloodwork marker

Get bloodwork marker. Returns data at bloodwork / :id / marker / :markerName. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
markerNamestringrequired

Lab Partners

4 endpoints

Order at-home and in-clinic blood panels through Healify's integrated lab partners (Probatix, Thriva, Homed-IQ, Terra) and receive results back as Bloodwork reports. The three order endpoints are JWT-authenticated and self-scoped (user_id) — a caller can only list panels and read or create their own orders. The fourth is the public, signature-verified webhook each partner calls to deliver finished results; it is not called by partner integrators directly but its contract is documented here for completeness.

GET /api/lab/panels List available lab test panels

Returns the purchasable lab panels for the requested partner and locale. Scoped to the authenticated user via JWT. Use the returned panelId when placing an order.

FieldTypeRequiredDescription
partnerKeystringoptionalQuery param. Lab partner to list panels for — one of PROBATIX, THRIVA, HOMEDIQ, TERRA. Omit to list across all configured partners.
localestringoptionalQuery param. Locale for panel names / pricing (e.g. en-GB).

Returns 200 with an array of panel objects:

FieldTypeRequiredDescription
panelIdstringrequiredPartner-scoped panel identifier (used when placing an order).
namestringrequiredHuman-readable panel name.
descriptionstringoptionalShort description of what the panel measures.
priceMinorUnitsnumberoptionalPrice in minor currency units (e.g. pence for GBP, cents for EUR).
currencystringoptionalISO 4217 currency code (e.g. GBP, EUR).
biomarkersstring[]optionalBiomarker names included in the panel.
POST /api/lab/order Place a lab order for the current user

Creates a lab order with the selected partner and panel for the authenticated user. The user is always taken from the JWT — never the body — so a caller can only order for themselves. When invoked via the Anna MCP tool this is a destructive operation and requires a confirmation token.

FieldTypeRequiredDescription
partnerKeystringrequiredLab partner key — one of PROBATIX, THRIVA, HOMEDIQ, TERRA.
panelCodestringrequiredPanel code to order (the partner-scoped panelId from GET /api/lab/panels).
shippingAddrobjectoptionalShipping address for at-home kit dispatch / phlebotomy (free-form string or structured object).

Returns 201 with the created lab order (including its id and initial PENDING status).

GET /api/lab/order/{id} Get one of the current user's lab orders

Returns a single lab order by id. Ownership is enforced — callers only see their own orders. Returns 404 when the order does not exist or belongs to another user.

FieldTypeRequiredDescription
idstringrequiredPath param. LabOrder id (cuid).

The status field follows the lab-order lifecycle: PENDINGCONFIRMEDPROCESSINGCOMPLETE, or CANCELLED / FAILED. When an order reaches COMPLETE the partner delivers results via the webhook below, which Healify ingests into a Bloodwork report.

POST /api/bloodwork/lab/webhook/{partnerKey} Lab partner webhook receiver (signature-verified)

Public, signature-verified callback that lab partners invoke to deliver finished results. No JWT — authenticity is proven by an HMAC-SHA256 signature over the raw request body. Healify verifies the signature, enqueues the event for asynchronous ingestion (normalisation → BloodReport → metrics), and returns immediately. This endpoint is implemented by Healify and consumed by the partner; integrators do not call it.

FieldTypeRequiredDescription
partnerKeystringrequiredPath param. Sending partner — one of probatix, thriva, homediq, terra (lowercase). Unknown keys return 400.
<body>jsonrequiredRaw partner result event. Must include a stable id field — Healify dedupes re-deliveries on {partnerKey}:{id}, so a repeated event is a safe no-op.

Signature scheme (per partner) — all use HMAC-SHA256 with a per-partner shared secret, compared in constant time:

PartnerHeaderSigned payloadReplay window
probatixX-Probatix-Signature: sha256=<hex>rawBody
thrivaX-Thriva-Signature: t=<unix>,v1=<hex>${t}.${rawBody}5 min
homediqX-HomedIQ-Signature: <hex>rawBody
terraterra-signature: t=<unix>,v1=<hex>${t}.${rawBody}5 min

For the timestamp schemes (Thriva, Terra), Healify rejects any request whose t is more than 5 minutes old or in the future. Always compute the HMAC over the exact raw bytes received — re-serialising the JSON will break the signature.

TypeScript — verify signature
import { createHmac, timingSafeEqual } from 'crypto';

// Probatix / Homed-IQ: HMAC over the raw body.
function verifyHmac(secret: string, rawBody: Buffer, providedHex: string): boolean {
  const expected = createHmac('sha256', secret).update(rawBody).digest();
  const provided = Buffer.from(providedHex, 'hex');
  return expected.length === provided.length && timingSafeEqual(expected, provided);
}

// Thriva / Terra: header is "t=<unix>,v1=<hex>"; sign `${t}.${rawBody}`.
function verifyTimestamped(secret: string, rawBody: Buffer, header: string): boolean {
  const parts = Object.fromEntries(header.split(',').map(s => s.split('=').map(x => x.trim())));
  const t = parseInt(parts.t, 10);
  if (!Number.isFinite(t) || Math.abs(Date.now() - t * 1000) > 5 * 60 * 1000) return false;
  const signed = Buffer.from(`${t}.${rawBody.toString('utf8')}`);
  const expected = createHmac('sha256', secret).update(signed).digest();
  const provided = Buffer.from(parts.v1, 'hex');
  return expected.length === provided.length && timingSafeEqual(expected, provided);
}
Python — verify signature
import hmac, hashlib, time

# Probatix / Homed-IQ: HMAC over the raw body.
def verify_hmac(secret: str, raw_body: bytes, provided_hex: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
    try:
        provided = bytes.fromhex(provided_hex)
    except ValueError:
        return False
    return hmac.compare_digest(expected, provided)

# Thriva / Terra: header is "t=<unix>,v1=<hex>"; sign f"{t}.{raw_body}".
def verify_timestamped(secret: str, raw_body: bytes, header: str) -> bool:
    parts = dict(p.strip().split('=', 1) for p in header.split(','))
    t = int(parts['t'])
    if abs(time.time() - t) > 5 * 60:
        return False
    signed = f"{t}.{raw_body.decode('utf-8')}".encode()
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).digest()
    try:
        provided = bytes.fromhex(parts['v1'])
    except ValueError:
        return False
    return hmac.compare_digest(expected, provided)

Status codes

CodeMeaning
200Event accepted and enqueued for ingestion. Returns { "received": true }.
400Unknown partnerKey, missing raw body, or malformed JSON payload.
401Signature verification failed (bad signature, missing/expired timestamp, or no secret configured).

Retry policy — Healify processes results on a background queue with 3 attempts and exponential backoff (2s base). Partners should treat any non-200 response as retryable; because ingestion is idempotent on {partnerKey}:{event.id}, re-delivering the same event is always safe.

DNA Analysis

13 endpoints
POST /api/dna/analyze Analyze DNA report with AI (Async)

Queue DNA analysis job for comprehensive AI-powered analysis. Analysis is processed asynchronously and user receives a push notification when complete. Results can be retrieved via GET /dna/reports/:reportId

FieldTypeRequiredDescription
reportIdstringrequiredDNA report ID to analyze
focusAreasstring[]optionalSpecific traits to focus analysis on
includeRecommendationsbooleanoptionalInclude health recommendations
GET /api/dna/can-upload Check if user can upload DNA

Check if user can upload DNA data. Returns false if user already has a validated DNA profile (DNA is immutable once validated).

POST /api/dna/confirm-upload Confirm presigned DNA upload and start analysis

Step 2 of 2: Called after the client has PUT the file to S3. Triggers DNA parsing and queues AI analysis.

FieldTypeRequiredDescription
keystringrequiredS3 key returned from presign (must be dna-raw/<userId>/…)
contentTypestringrequired
providerstringrequired
POST /api/dna/presign-upload Get presigned S3 URL for direct DNA file upload

Step 1 of 2: Returns a presigned S3 PUT URL for direct client-side upload. Call POST /dna/confirm-upload after uploading.

FieldTypeRequiredDescription
fileNamestringrequired
contentTypestringrequired
fileSizenumberrequiredFile size in bytes
DELETE /api/dna/report Delete the authenticated user DNA report

Permanently deletes the user's uploaded DNA file + derived SNP analysis. Irreversible. Idempotent: returns success even when nothing exists. Phase 8 destructive op — requires confirmation_token from MCP confirmation flow.

GET /api/dna/reports Get all DNA reports for user

Retrieve list of uploaded DNA reports

GET /api/dna/reports/{reportId} Get specific DNA report

Retrieve detailed information about a specific DNA report

FieldTypeRequiredDescription
reportIdstringrequired
POST /api/dna/upload Upload DNA raw data file

Upload 23andMe, AncestryDNA, or similar raw DNA data files

FieldTypeRequiredDescription
filestringrequiredDNA raw data file (.txt, .csv, .zip, .pdf, or image)
providerstringoptionalDNA provider (e.g., 23andme, ancestrydna)
GET /api/dna/variants Query annotated genomic variants by gene or rsID

Returns annotated genomic variants from the user's DNA analysis. Query by gene symbol (e.g., BRCA1) or rsID (e.g., rs1801133). Use when the user asks about genetic risk factors, specific gene variants, or pharmacogenomics data. Returns variant details including clinical significance and allele frequencies.

FieldTypeRequiredDescription
genestringoptionalGene symbol (e.g. BRCA1) (in query)
rsIdstringoptionalLegacy rsID query param name (capital I); prefer rsid (in query)
rsidstringoptionalrsID (e.g. rs1801133) (in query)
POST /api/dna/vcf-confirm Trigger genomic annotation workflow after VCF upload

Confirms a VCF file upload and starts the AWS HealthOmics annotation workflow. Use after the user has successfully uploaded their VCF file via the presigned URL. Returns a workflow run ID to track progress.

GET /api/dna/vcf-status/{dnaReportId} Get VCF annotation workflow status

Returns the current HealthOmics annotation workflow status for the given DNA report. Use to check if the genomic analysis is complete, in progress, or failed. Returns status, progress percentage, and any error details.

FieldTypeRequiredDescription
dnaReportIdstringrequired
POST /api/dna/vcf-upload Get presigned S3 URL for VCF genomic file upload

Returns a presigned PUT URL that allows the client to upload a VCF (Variant Call Format) genomic file directly to S3 without routing through the API server. Valid for 15 minutes. Use when the user wants to upload their DNA/genomic data for analysis.

FieldTypeRequiredDescription
filenamestringrequiredVCF filename (e.g. sample.vcf or sample.vcf.gz)
GET /api/genetics/dna-profile Get DNA profile

Retrieve user DNA profile and genetic insights (alias for /dna/reports)

Goals

5 endpoints
GET /api/goals Get user goals

Retrieve all health goals for the current user including progress tracking, milestones, and target dates.

POST /api/goals Create user goals

Create new health goals with target values, deadlines, and tracking milestones. Supports weight loss, fitness, nutrition, and other health objectives.

FieldTypeRequiredDescription
mainGoalstringoptionalMain goal of the user
secondaryGoalsstring[]optionalSecondary goals
challengesstring[]optionalChallenges the user faces
relatedMetricsobjectoptionalRelated metrics and measurements. Numeric values sent as strings (e.g. "70") are automatically coerced to numbers.
descriptionstringoptionalAlternative field for main goal (deprecated, use mainGoal instead)
goalTypestringoptionalGoal type: qualitative (text-based) or quantitative (tracked with target value)
targetValuenumberoptionalNumeric target value for quantitative goals (e.g. 70 for 70 kg)
targetUnitstringoptionalUnit for the target value (e.g. kg, steps, hours)
deadlinestringoptionalGoal deadline as ISO 8601 date string
statusstringoptionalGoal lifecycle status
currentValuenumberoptionalCurrent progress value for quantitative goals (updated automatically by wearable data)
milestonesstring[]optionalMilestone checkpoints for the goal
PUT /api/goals Update user goals

Update or create health goals with target values, deadlines, and tracking milestones. Supports weight loss, fitness, nutrition, and other health objectives.

FieldTypeRequiredDescription
mainGoalstringoptionalMain goal of the user
secondaryGoalsstring[]optionalSecondary goals
challengesstring[]optionalChallenges the user faces
relatedMetricsobjectoptionalRelated metrics and measurements. Numeric values sent as strings (e.g. "70") are automatically coerced to numbers.
descriptionstringoptionalAlternative field for main goal (deprecated, use mainGoal instead)
goalTypestringoptionalGoal type: qualitative (text-based) or quantitative (tracked with target value)
targetValuenumberoptionalNumeric target value for quantitative goals (e.g. 70 for 70 kg)
targetUnitstringoptionalUnit for the target value (e.g. kg, steps, hours)
deadlinestringoptionalGoal deadline as ISO 8601 date string
statusstringoptionalGoal lifecycle status
currentValuenumberoptionalCurrent progress value for quantitative goals (updated automatically by wearable data)
milestonesstring[]optionalMilestone checkpoints for the goal
GET /api/goals/progress Get goal progress with milestone evaluation

Get goal progress with milestone evaluation. Returns data at goals / progress. Authenticated endpoint — honours the caller's JWT for per-user scope.

DELETE /api/goals/{id} Delete a specific goal by id (owner-scoped)

Permanently removes the goal with the given id. Only the owning user may delete their own goal. Returns 404 if the goal is not found or does not belong to the user.

FieldTypeRequiredDescription
idnumberrequired

Habits

9 endpoints
GET /api/habits Get active habits and progress for a date

Get active habits and progress for a date. Returns data at habits. Authenticated endpoint — honours the caller's JWT for per-user scope.

POST /api/habits/complete Mark a habit as done for today (mobile shorthand)

Mark a habit as done for today (mobile shorthand). Accepts and processes data at habits / complete. Authenticated endpoint — honours the caller's JWT for per-user scope.

POST /api/habits/manual Create manual habits in user_habits

Create manual habits in user_habits. Accepts and processes data at habits / manual. Authenticated endpoint — honours the caller's JWT for per-user scope.

GET /api/habits/overview/weekly Get weekly habit overview bars

Get weekly habit overview bars. Returns data at habits / overview / weekly. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
weekStartstringrequiredISO 8601 date string for the start of the week (Monday). Required. (in query)
POST /api/habits/recommendations Generate habit recommendations (not persisted)

Generate habit recommendations (not persisted). Accepts and processes data at habits / recommendations. Authenticated endpoint — honours the caller's JWT for per-user scope.

POST /api/habits/recommendations/select Save selected recommended habits to user_habits

Save selected recommended habits to user_habits. Accepts and processes data at habits / recommendations / select. Authenticated endpoint — honours the caller's JWT for per-user scope.

PATCH /api/habits/{habitId} Update a habit definition (duration / cadence)

Update a habit's definition fields (target value, unit, frequency type/target, schedule days) at habits / :habitId. Authenticated endpoint — honours the caller's JWT for per-user scope. Log state (value/completed) is owned by the log endpoint, not this one.

DELETE /api/habits/{habitId} Delete a habit (owner-scoped)

Permanently removes the user's own habit and all associated logs. Owner-scoped: a user can only delete their own habits. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
habitIdstringrequired
POST /api/habits/{habitId}/log Upsert habit log for a date (habit_id + log_date)

Upsert habit log for a date (habit_id + log_date). Accepts and processes data at habits / :habitId / log. Authenticated endpoint — honours the caller's JWT for per-user scope.

Fitness

17 endpoints
GET /api/exercises List or search exercises with optional filters

List or search exercises with optional filters. Returns data at exercises. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
qstringoptionalText search query (name, muscle, equipment) (in query)
bodyPartstringoptionalFilter by body part (e.g. chest, back, legs) (in query)
equipmentstringoptionalFilter by equipment (e.g. barbell, dumbbell, bodyweight) (in query)
muscleGroupstringoptionalFilter by muscle group (matches target_muscle, secondary_muscles, or exercise_muscle_groups) (in query)
categorystringoptionalFilter by category (in query)
limitstringoptionalNumber of results to return (max 100) (in query)
includeCustomstringoptionalInclude custom exercises for the calling user (default: true) (in query)
POST /api/exercises/custom Create a custom exercise for the current user

Create a custom exercise for the current user. Accepts and processes data at exercises / custom. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
namestringrequiredExercise name
targetMusclesstring[]requiredTarget muscle groups
equipmentstringrequiredEquipment type
bodyPartstringoptionalPrimary body part
instructionsstring[]optionalInstructions array
descriptionstringoptionalExercise description
GET /api/exercises/{id}/progress Get per-exercise weight/volume/1RM progress history

Get per-exercise weight/volume/1RM progress history. Returns data at exercises / :id / progress. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
POST /api/fitness/programs Create a workout program template (manual or AI-generated)

Create a workout program template (manual or AI-generated). Accepts and processes data at fitness / programs. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
namestringrequired
descriptionstringoptional
goalstringoptionalFitness goal (e.g. strength, weight_loss, muscle_gain)
difficultystringoptional
durationWeeksnumberoptional
daysPerWeeknumberoptional
exercisesobject[]required
sourcestringoptional
isActivebooleanoptionalWhen true, program is published (included in weekly schedule and AI context). New programs default to false (draft / hidden).
coachingNotesstring[]optionalProgram-level AI coaching notes
GET /api/fitness/programs List user workout programs (slim, paginated)

List user workout programs (slim, paginated). Returns data at fitness / programs. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
limitnumberoptional (in query)
offsetnumberoptional (in query)
GET /api/fitness/programs/weekly Get this week's scheduled programs

Get this week's scheduled programs. Returns data at fitness / programs / weekly. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
timezonestringoptionalIANA timezone (e.g. America/Los_Angeles) for user's current weekday (in query)
GET /api/fitness/programs/{id} Get program detail (full nested with exercises)

Get program detail (full nested with exercises). Returns data at fitness / programs / :id. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
PUT /api/fitness/programs/{id} Update program template

Update program template. Replaces data at fitness / programs / :id. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
namestringoptional
descriptionstringoptional
goalstringoptionalFitness goal (e.g. strength, weight_loss, muscle_gain)
difficultystringoptional
durationWeeksnumberoptional
daysPerWeeknumberoptional
exercisesobject[]optional
sourcestringoptional
isActivebooleanoptionalWhen true, program is published (included in weekly schedule and AI context). New programs default to false (draft / hidden).
coachingNotesstring[]optionalProgram-level AI coaching notes
DELETE /api/fitness/programs/{id} Soft-delete program template

Soft-delete program template. Removes data at fitness / programs / :id. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
POST /api/fitness/programs/{id}/schedule Assign program to weekdays

Assign program to weekdays. Accepts and processes data at fitness / programs / :id / schedule. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
mondaybooleanoptional
tuesdaybooleanoptional
wednesdaybooleanoptional
thursdaybooleanoptional
fridaybooleanoptional
saturdaybooleanoptional
sundaybooleanoptional
GET /api/fitness/sessions List session history (slim, paginated). Pass healthkit_synced=false to get unsynced completed sessions.

List session history (slim, paginated). Pass healthkit_synced=false to get unsynced completed sessions.. Returns data at fitness / sessions. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
limitnumberoptional (in query)
offsetnumberoptional (in query)
from_datestringoptional (in query)
to_datestringoptional (in query)
healthkit_syncedstringoptionalFilter: false = return only unsynced completed sessions (in query)
POST /api/fitness/sessions/start Start a workout session (creates DB record immediately)

Start a workout session (creates DB record immediately). Accepts and processes data at fitness / sessions / start. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
programIdnumberoptionalProgram template ID to base this session on
sessionNamestringoptionalOptional custom session name
GET /api/fitness/sessions/{id} Get session detail (full nested with exercises and sets)

Get session detail (full nested with exercises and sets). Returns data at fitness / sessions / :id. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
POST /api/fitness/sessions/{id}/abandon Abandon a session (no HealthKit write-back)

Abandon a session (no HealthKit write-back). Accepts and processes data at fitness / sessions / :id / abandon. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
POST /api/fitness/sessions/{id}/complete Complete session — batch-POST all exercises and sets

Complete session — batch-POST all exercises and sets. Accepts and processes data at fitness / sessions / :id / complete. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
exercisesobject[]requiredAll exercises logged in this session
POST /api/fitness/sessions/{id}/healthkit-sync Confirm HealthKit write-back for a session

Confirm HealthKit write-back for a session. Accepts and processes data at fitness / sessions / :id / healthkit-sync. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
idnumberrequired
GET /api/fitness/summary/today Get today's fitness activity ring summary (V2)

Returns today's Apple Watch activity rings (move/exercise/stand) with values, goals, and progress fractions, plus an optional recovery score derived from HRV and resting heart rate. Use when the user asks about their activity rings, move/exercise/stand progress, or recovery status. Always check hasData per ring before interpreting values — hasData: false means Apple Watch has not synced data for that ring today, not that the user is sedentary. recoveryAvailable: false means recoveryScore is null due to insufficient HRV history (fewer than 3 nights) — do not interpret null as poor recovery.

Meal Plans

6 endpoints
GET /api/mealplan Get current meal plan for the user

Retrieve the user's current AI-generated meal plan. Returns null if no meal plan has been generated yet. Use when the user asks to see their existing meal plan or wants to check what meals are planned.

POST /api/mealplan Regenerate meal plan from scratch

Queue a fresh AI-generated meal plan, replacing the existing one. Resets the nutrition profile and enqueues a background generation job. The user receives a push notification when the new plan is ready. Use when the user wants a completely new meal plan.

GET /api/mealplan/getOrCreate Get existing meal plan or create a new one

Retrieve the current meal plan or automatically generate a new one if none exists. This is the recommended endpoint for most use cases as it handles both scenarios. Use when the user wants their meal plan and you want to ensure they always get one. Requires subscription or free-tier usage.

GET /api/mealplan/nutrition-profile Get user nutrition profile (dietary preferences)

Retrieve the nutrition profile containing dietary preferences, allergies, calorie targets, and macro splits. Use when the user asks about their dietary settings or before generating a meal plan to check current preferences.

POST /api/mealplan/nutrition-profile Update user nutrition profile (dietary preferences)

Update the nutrition profile with dietary preferences, allergies, calorie targets, and macro distribution. Use when the user changes their dietary preferences, reports new allergies, or adjusts calorie goals. This affects future meal plan generation.

DELETE /api/mealplan/nutrition-profile Delete user nutrition profile

Delete the nutrition profile, which triggers regeneration of the meal plan on the next request. Use when the user wants to start fresh with their dietary preferences.

Meditation

10 endpoints
GET /api/meditation/events/{jobId} Stream dual-stream meditation events via SSE

Proxies SSE events from meditation-service for dual-stream playback. Events: music (instant library music URL), voice_stream (HLS voice URL), complete (mastered audio URL), error. Use for real-time meditation audio streaming with separate music and voice channels.

FieldTypeRequiredDescription
jobIdstringrequired
POST /api/meditation/generate Generate a personalized meditation session (async)

Submits a meditation generation job and returns a jobId immediately for polling. Use when the user requests a new meditation. Specify type (focus, sleep, stress, etc.), duration, and voice preferences. Requires active subscription or free-tier usage.

FieldTypeRequiredDescription
typestringrequiredType of meditation to generate
durationnumberrequiredDuration in seconds
focusstringoptionalUser focus/intention for the session
healthContextobjectoptionalUser health context for personalization
thread_idstringoptionalChat thread ID for associating completion message (chat-initiated meditations)
voiceGeneratorstringoptionalTTS provider: elevenlabs, cartesia, or openai
backgroundMusicbooleanoptionalWhether to include background music (default: true)
enableKaraokebooleanoptionalWhether to enable karaoke mode (word-level TTS timing for lyric display)
GET /api/meditation/jobs List meditation jobs for the current user

Returns all meditation generation jobs for the authenticated user, ordered by creation date descending. Use when the user wants to see their meditation history or replay a previous session. Supports filtering by status and pagination.

FieldTypeRequiredDescription
statusstringoptionalFilter by job status (in query)
limitnumberoptionalMax results (default 50) (in query)
POST /api/meditation/jobs Create meditation job tracking record

Creates a meditation job entry in the database for tracking generation progress. Use after initiating meditation generation to register the job for status polling and webhook handling.

POST /api/meditation/jobs/{jobId}/listen Record a completed meditation listen session

Records that the user listened to a meditation until the end or past the completion threshold. Use when the meditation player reports playback completion. Tracks listen history for coaching insights and streak tracking.

FieldTypeRequiredDescription
jobIdstringrequired
GET /api/meditation/listen-sessions List meditation listen sessions for the current user

Returns all listen sessions for the authenticated user, ordered by most recent first. Each row represents one completed meditation playback. Use when the user asks about their meditation history or for tracking meditation consistency.

FieldTypeRequiredDescription
limitnumberoptionalMax results (default 50) (in query)
GET /api/meditation/progress/{jobId} Get meditation generation progress (lightweight)

Lightweight polling endpoint for meditation job progress with caching. Use for frequent polling during meditation generation to update progress bars without heavy DB lookups.

FieldTypeRequiredDescription
jobIdstringrequired
GET /api/meditation/status/{jobId} Get meditation generation job status

Polls for the current status of a meditation generation job including progress percentage, current stage, and URLs when complete. Use to check if a meditation the user requested is ready for playback.

FieldTypeRequiredDescription
jobIdstringrequired
GET /api/meditation/stream/{jobId} Stream meditation generation progress via SSE

Proxies the SSE stream from meditation-service for a given job. Use for real-time progress updates during meditation generation. Returns Server-Sent Events with progress, stage, and completion data.

FieldTypeRequiredDescription
jobIdstringrequired
GET /api/meditation/voices List available TTS voices for meditation

Returns available meditation TTS voices from the meditation service. Falls back to a static list if the service is unreachable. Use when the user wants to choose a voice for their meditation session.

Recommendations

8 endpoints
GET /api/recommendations Get personalized product recommendations for the user

Returns personalized health product recommendations based on the user's health profile, goals, and preferences. Use when the user asks about supplements, health products, or visits the Shop tab. Supports filtering by category and pagination via limit parameter.

FieldTypeRequiredDescription
categorystringrequired (in query)
GET /api/recommendations/categories Get available product recommendation categories

Returns the list of product categories available in the recommendation catalog (e.g., supplements, fitness equipment, sleep aids). Use to populate category filters in the Shop tab.

POST /api/recommendations/click Record a product recommendation click event

Records that the user clicked on a product recommendation. Use for engagement tracking and recommendation quality improvement.

POST /api/recommendations/commerce Create a data-backed commerce recommendation (Anna service token or authenticated user)

Called by the Anna agentcore surface_recommendation tool when Anna has explicit health data evidence for a product gap. Anna service-token callers may specify any userId. User-JWT callers may only create recommendations for their own account.

FieldTypeRequiredDescription
userIdnumberrequiredUser ID (numeric).
productCategorystringrequiredProduct category slug (e.g. "vitamin_d_supplement").
rationalestringrequiredHuman-readable evidence string explaining the recommendation.
dataSourcestringrequiredHealth data field that backs this recommendation (e.g. "bloodwork.vitaminD").
affiliateUrlobjectoptionalAffiliate URL — must be from an approved affiliate domain. Null until v1.6.
POST /api/recommendations/consent Set affiliate recommendation consent for FTC compliance

Records the user's consent for receiving affiliate product recommendations. Required for FTC compliance before showing monetized recommendations. Use when the user opts in or out of affiliate recommendations.

GET /api/recommendations/consent Get affiliate recommendation consent state for the current user

Returns whether the user has consented to affiliate product recommendations. Use to check consent status before displaying monetized product suggestions.

POST /api/recommendations/follow-up-complete Record follow-up action completion for a product recommendation

Records that the user completed a follow-up action on a product recommendation (e.g., purchased, added to cart). Use for tracking recommendation engagement and improving future suggestions.

GET /api/recommendations/history Get product recommendation click history for the current user

Returns the user's recent product recommendation click history with timestamps. Use to understand user product interests or avoid recommending already-viewed products.

Insights

6 endpoints
GET /api/causality/cards List causality cards for the current user

Returns Food→body causality cards (HEA-4293): paginated, excluding dismissed entries by default. Uses an opaque cursor for stable pagination.

FieldTypeRequiredDescription
limitnumberoptional (in query)
cursorstringoptionalOpaque pagination cursor from previous response (in query)
unshownOnlybooleanoptionalWhen true, return only cards not yet shown/dismissed (in query)
GET /api/causality/cards/{id} Get a single causality card

Loads one causality card by UUID for the detail screen and records an analytics view event (Amplitude). Returns 404 if the card does not exist or belongs to another user.

FieldTypeRequiredDescription
idstringrequired
POST /api/causality/cards/{id}/dismiss Dismiss a causality card

Soft-dismisses a card for the current user (sets dismissedAt) so it no longer appears in default lists. Optional secondsViewed supports dismiss-rate quality metrics.

FieldTypeRequiredDescription
idstringrequired
secondsViewednumberoptionalApproximate seconds the card was visible before dismiss
POST /api/causality/cards/{id}/share Record that the user shared a causality card

Increments share count, stamps last share channel when provided, updates sharedAt, and emits an analytics event for funnel measurement.

FieldTypeRequiredDescription
idstringrequired
channelstringoptionalShare channel label for analytics (e.g. instagram_story, copy_link)
GET /api/users/me/biological-age Compute biomarker-based biological age

Returns an estimated biological age derived from the past 30 days of HealthKit data (resting HR, HRV, sleep score, VO2 max). Confidence reflects how many biomarkers had sufficient data. Returns a null-shaped result with confidence=0 when no data is available. DNA layer is V2 — this MVP uses biomarkers only.

GET /api/users/me/morning-briefing-context Fetch morning briefing context for the current user

Returns a structured snapshot of yesterday health data (sleep, HRV, resting HR, energy score), the latest causality card, and the top recommended habit. Called by AgentCore to compose the voice morning briefing. Free-text fields are PHI-sanitized before return. nextCalendarEvent is always null until a calendar integration is available.

Reports

2 endpoints
GET /api/report/monthly Get monthly report

Get monthly report. Returns data at report / monthly. Authenticated endpoint — honours the caller's JWT for per-user scope.

GET /api/report/weekly Get weekly report

Get weekly report. Returns data at report / weekly. Authenticated endpoint — honours the caller's JWT for per-user scope.

Check-ins

3 endpoints
GET /api/checkup Get checkup question

Get checkup question. Returns data at checkup. Authenticated endpoint — honours the caller's JWT for per-user scope.

POST /api/checkup Post checkup question

Post checkup question. Accepts and processes data at checkup. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
questionstringoptional
answerstringoptional
questionIdstringoptionalOptional question identifier sent by consumer
POST /api/checkup/custom Post custom checkup question

Post custom checkup question. Accepts and processes data at checkup / custom. Authenticated endpoint — honours the caller's JWT for per-user scope.

FieldTypeRequiredDescription
questionstringoptional
answerstringoptional
questionIdstringoptionalOptional question identifier sent by consumer

Milestones

5 endpoints
GET /api/achievement/{userId} List a user's unlocked achievements (owner only)

Returns all unlocked achievements for the given userId. Restricted to the authenticated user's own data — returns 403 if userId does not match the caller's JWT subject.

FieldTypeRequiredDescription
userIdnumberrequired
GET /api/milestone Get all milestones for the current user

Returns all health milestones awarded to the authenticated user (weight goals, streak achievements, habit formation, etc.). Use when the user asks about their achievements or for gamification displays.

GET /api/milestone/pending Get unviewed milestones pending celebration

Returns milestones that have been awarded but not yet viewed by the user. Use to trigger celebration UI or congratulatory coaching messages when the user opens the app.

POST /api/milestone/{id}/shared Record milestone share and get shareable URL

Records that the user shared a milestone and returns a shareable URL for referral loop. Use when the user wants to share a health achievement on social media or with friends.

FieldTypeRequiredDescription
idnumberrequired
POST /api/milestone/{id}/viewed Mark a milestone as viewed by the user

Marks a specific milestone as viewed, dismissing the celebration UI. Use after the user has seen the milestone celebration screen.

FieldTypeRequiredDescription
idnumberrequired

Notifications

4 endpoints
GET /api/notification Get all notifications for the current user (paginated)

Returns paginated notification history for the authenticated user. Use when the user wants to see their notification feed or check past health reminders, milestone celebrations, and coaching messages. Supports cursor-based pagination.

FieldTypeRequiredDescription
takenumberoptionalNumber of notifications to return (default 100, max 200) (in query)
cursornumberoptionalCursor (last notification ID) for pagination (in query)
POST /api/notification/generate-ai Request an AI-generated personalized notification now

Triggers an immediate AI-generated notification using full health context (HealthKit, DNA, bloodwork, sleep, etc.). Respects throttling limits. Use when the agent wants to proactively send the user a personalized health insight or coaching nudge.

POST /api/notification/read Mark notifications as read by IDs

Marks the specified notification IDs as read for the authenticated user. Use when the user opens or dismisses notifications in the app.

GET /api/notification/unread Get unread notifications for the current user

Returns only unread notifications for the authenticated user. Use to display a badge count or unread notification list in the app.

Feedback

1 endpoint
POST /api/feedback Create feedback

Create feedback. Accepts and processes data at feedback. Authenticated endpoint — honours the caller's JWT for per-user scope.

Voice

3 endpoints
GET /api/voice/anna-token Get voice anna-token

Get voice anna-token. Returns data at voice / anna-token. Authenticated endpoint — honours the caller's JWT for per-user scope.

POST /api/voice/transcribe Create voice transcribe

Create voice transcribe. Accepts and processes data at voice / transcribe. Authenticated endpoint — honours the caller's JWT for per-user scope.

POST /api/voice/v1/chat/completions Create voice v1 chat completions

Create voice v1 chat completions. Accepts and processes data at voice / v1 / chat / completions. Authenticated endpoint — honours the caller's JWT for per-user scope.

Attachments

3 endpoints
POST /api/document/route Smart-route a chat-attached document to the right handler

Classifies the uploaded document and directs Anna to refer the user into the correct flow: bloodwork → Bloodwork upload screen, dna → DNA upload screen, other → general Anna acknowledgement. Accepts PDF, plain-text, CSV, and ZIP archives (DNA exports). ZIP files are classified by filename heuristic only — never opened or parsed.

FieldTypeRequiredDescription
documentstringrequired
messagestringoptionalOptional caption or question the user typed with the document.
POST /api/image-storage/upload Upload health-related image to cloud storage

Upload and store a health-related image (bloodwork photos, meal photos, progress photos, avatar). Returns the public URL of the uploaded image. Max file size 10MB. Use when the user wants to upload a photo for health tracking or profile purposes.

FieldTypeRequiredDescription
filestringrequired
POST /api/image/route Smart-route a chat-attached image to the right handler

Classifies the uploaded photo and forwards it to the right specialist: food → existing analyze-food-photo flow, skin / body / wearable / document / other → AgentCore Anna with image context, bloodwork → existing bloodwork upload-and-analyze flow. Use this endpoint for EVERY chat-attached image so the server picks the right path; never route directly to analyze-food-photo from the chat composer.

FieldTypeRequiredDescription
photostringrequired
messagestringoptionalOptional caption or question the user typed with the image.
forceCategorystringoptionalOptional override — skips classification and routes directly to the named handler.

Subscriptions

8 endpoints
GET /api/subscriptions Get current user subscription status

Returns the subscription tier, status, expiration, and trial state for the authenticated user. Use before offering premium features to check if the user has an active subscription. Alias for GET /subscriptions/status.

PUT /api/subscriptions Update current user subscription tier

Updates the subscription tier and status for the authenticated user. Use when processing subscription changes from the app store or admin actions.

FieldTypeRequiredDescription
revenueCatUserIdstringoptionalRevenueCat user ID
revenueCatAliasesstring[]optionalRevenueCat aliases for this user
subscriptionStatusstringoptionalSubscription status
subscriptionPlanstringoptionalSubscription plan identifier
subscriptionStartDatestringoptionalSubscription start date
subscriptionEndDatestringoptionalSubscription end date
trialStartDatestringoptionalTrial start date
trialEndDatestringoptionalTrial end date
isTrialActivebooleanoptionalWhether trial is currently active
hasUsedTrialbooleanoptionalWhether user has used their trial
POST /api/subscriptions/cancel Cancel the authenticated user subscription

Cancels the current RevenueCat subscription at end-of-period. Idempotent: returns { success: true, already_cancelled: true } if no active subscription exists. Phase 8 destructive op — requires confirmation_token from MCP confirmation flow.

GET /api/subscriptions/status Get current user subscription status and tier details

Returns detailed subscription status including tier (free, premium, trial), expiration date, and whether the user is in a trial period. Use to determine feature access before calling premium-only endpoints.

POST /api/subscriptions/trial/start Start 7-day premium trial for the current user

Activates a 7-day free trial of premium features for the authenticated user. Use when the user wants to try premium features. Fails if the user has already used their trial or has an active trial.

GET /api/subscriptions/usage Get current user feature usage counts and limits

Returns usage counts and limits for gated features (chat messages, meal plans, bloodwork analyses, meditations). Use to check remaining free-tier usage before calling a gated endpoint.

GET /api/users/me/freemium-state Get freemium state for current user

Returns tier (trial | free | paid), trial window, and per-feature counters. Mobile polls this on app open and after each feature action.

POST /api/users/me/freemium-state/increment Increment feature usage counter (atomic)

MUST be called before invoking any gated feature. Uses Redis INCR for atomicity — parallel requests cannot both succeed past the limit. Returns allowed:false + reason when limit is hit; mobile MUST show paywall instead of feature.

FieldTypeRequiredDescription
featurestringrequiredFeature to increment usage counter for

Integrations

6 endpoints
GET /api/integrations List connected services for the current user

Returns all active service integrations for the authenticated user.

GET /api/integrations/catalog Get the curated connector catalog

Returns all supported health connectors with their display name, source (pipedream or open-wearables), and availability status. Use this to drive UI tile rendering. Apple Health is excluded (native HealthKit integration). "coming_soon" tiles are gated pending provider credential provisioning.

POST /api/integrations/connect Initiate a service connection via Pipedream Connect

Generates a Pipedream Connect token and returns a URL the mobile app or web opens for OAuth. Supported services: fitbit, google-fit-developer-app, withings, strava. Pass platform="web" to receive web-compatible redirect URIs.

FieldTypeRequiredDescription
appSlugstringrequiredPipedream app slug for the service to connect
platformstringoptionalPlatform initiating the connection. Determines OAuth redirect URIs.
POST /api/integrations/open-wearables/connect Initiate an Open Wearables provider connection

Proxies a connect-initiation request to the Open Wearables aggregator for the given provider (oura, whoop, garmin). Returns an OAuth URL for the user to complete. Returns 503 when the provider credentials have not yet been provisioned — these are gated until the respective developer app secrets are configured.

FieldTypeRequiredDescription
providerstringrequiredOpen Wearables provider to connect
platformstringoptionalPlatform initiating the connection. Determines OAuth redirect URI.
DELETE /api/integrations/{service} Disconnect a service integration

Marks the integration as revoked (soft delete). The user can reconnect later.

FieldTypeRequiredDescription
servicestringrequiredService slug to disconnect
POST /api/integrations/{service}/fetch Fetch health data from a connected wearable service

Fetch health data from a connected wearable service via Pipedream proxy. Use when the user asks about their Fitbit steps, Strava activities, Withings weight, or Google Fit data.

FieldTypeRequiredDescription
servicestringrequiredService slug to fetch data from
metricTypestringrequiredMetric type to fetch: steps, heart_rate, sleep, weight, activities, calories, blood_pressure
startDatestringrequiredStart date (YYYY-MM-DD)
endDatestringrequiredEnd date (YYYY-MM-DD)

User & Auth

18 endpoints
POST /api/user Create a new user profile

Creates a new user record with the provided profile data. Use during initial registration when a user account needs to be provisioned after authentication. Returns the created user object.

FieldTypeRequiredDescription
appleIdstringoptional
emailstringoptional
namestringoptional
passwordstringoptional
DELETE /api/user Delete current user account

Permanently deletes the authenticated user account and all associated data. Use when the user explicitly requests account deletion. This action is irreversible.

GET /api/user Get current user profile and settings

Returns the full user profile for the authenticated user including demographics, health goals, dietary preferences, onboarding status, and notification settings. Use when the agent needs user context for personalized coaching or when the user asks about their profile.

PUT /api/user Update current user profile

Updates the authenticated user profile fields (weight, height, age, gender, activity level, health goals, dietary preferences, etc.). Use when the user provides updated personal information or changes their health goals.

FieldTypeRequiredDescription
namestringrequired
emailstringrequired
unitsobjectrequired
heightnumberrequired
weightnumberrequired
sexobjectrequired
agenumberrequired
heightUnitstringoptional
weightUnitstringoptional
onboardingCompletedbooleanrequired
isLoggedInbooleanrequired
pushTokenstringrequired
dateOfBirthstringoptional
avatarstringrequired
languagestringoptional
onboardingSourcestringoptional
focusesobjectoptionalUser health focus areas (array of strings or focus objects)
threadIdstringrequired
lastCriticalReportstringoptional
lastNonCriticalReportstringoptional
POST /api/user/appsflyer-id Store AppsFlyer attribution identifiers for the authenticated user

Called by the mobile app immediately after the AppsFlyer SDK resolves the install UID. Persists appsflyerId, IDFA (if ATT authorised), and IDFV so the backend can fire server-to-server events (renewals, refunds, dunning) on behalf of this user.

FieldTypeRequiredDescription
appsflyerIdstringrequiredAppsFlyer UID returned by the mobile SDK (appsFlyer.getAppsFlyerUID())
idfastringoptionaliOS IDFA — only present when ATT is authorised
idfvstringoptionaliOS IDFV — always present on iOS, never null
GET /api/user/dashboard Get user dashboard data with health summary

Returns aggregated dashboard data for the authenticated user including health score, recent metrics, streak info, and quick-glance cards. Use when rendering the main home screen or when the user asks for an overview of their health status.

POST /api/user/data-backup Create a data backup for the current user

Stores a client-side data backup snapshot for the authenticated user. Use when the mobile app needs to persist a local state backup to the server for recovery purposes.

POST /api/user/destructive-intent Mint a short-lived confirmation token for a destructive operation

Returns a prefixed token and the exact phrase the user must confirm. Token expires in 60 seconds. A 409 is returned if another destructive token is already active for this user.

FieldTypeRequiredDescription
mcp_aliasstringrequiredThe manifest alias of the destructive operation to confirm
contextobjectoptional
POST /api/user/focus-unlock Record focus area unlock for gamification

Records that the user has unlocked a new focus area (e.g., nutrition, sleep, fitness). Use when the user completes a health domain milestone that grants access to a new coaching focus area.

FieldTypeRequiredDescription
focusTypestringrequiredFocus type being unlocked
GET /api/user/focus-unlocks Get unlocked focus areas for gamification progress

Returns the list of focus areas the user has unlocked through health milestones. Use to display gamification progress or determine which coaching domains are available to the user.

PATCH /api/user/language Update user language preference

Sets the preferred language for the authenticated user. Use when the user wants to change their app language. Affects AI coaching language and notification language.

GET /api/user/notification-preferences Get notification preferences for the current user

Returns the notification preference settings (push, email, reminders, coaching tips) for the authenticated user. Use when checking which notification channels are enabled before sending a notification.

PATCH /api/user/notification-preferences Update notification preferences for the current user

Updates which notification channels and types are enabled for the authenticated user. Use when the user wants to toggle push notifications, email alerts, coaching reminders, or other notification categories.

FieldTypeRequiredDescription
profileUpdatesbooleanoptionalReceive push notifications when health profile is updated (e.g. after bloodwork/DNA)
dnaInsightsbooleanoptionalReceive push notifications for DNA insights (medication safety, genetic findings)
proactiveInsightsbooleanoptionalReceive proactive AI insight nudges
mealPlanbooleanoptionalReceive meal plan notifications
bloodworkbooleanoptionalReceive bloodwork report notifications
meditationbooleanoptionalReceive meditation session notifications
checkupRemindersbooleanoptionalReceive checkup reminder notifications
chatbooleanoptionalReceive chat message notifications
proactiveSessionsbooleanoptionalEnable per-user timezone-aware proactive check-in sessions via EventBridge Scheduler. When true, a dedicated schedule fires at 9 AM local time daily. When false, the schedule is deleted.
suppressWearableNudgesbooleanoptionalSuppress all in-app wearable/Apple Watch nudges and omit wearable references from AI coaching. Set to true when user confirms they do not use Apple Watch.
GET /api/user/onboarding Get user onboarding status and profile basics

Returns onboarding completion flag plus basic profile fields (weight, height, age, gender, activity level, health goals, dietary preferences). Use when checking if the user has completed initial setup or to retrieve quick profile context.

POST /api/user/onboarding Complete user onboarding (DEPRECATED)

DEPRECATED: Use POST /api/user/setup instead. This endpoint is kept for backward compatibility and will be removed in a future version.

FieldTypeRequiredDescription
healthGoalsstring[]requiredUser health goals
dietaryPreferencesstring[]requiredUser dietary preferences
activityLevelstringrequiredUser activity level
heightnumberrequiredUser height in cm
weightnumberrequiredUser weight in kg
agenumberrequiredUser age
genderstringrequiredUser gender
GET /api/user/recommendations/{metricName} Get health recommendations for a specific metric

Returns personalized health recommendations for the specified metric name (e.g., sleep, stress, activity). Use when the user asks for advice about a particular health area.

FieldTypeRequiredDescription
metricNamestringrequired
POST /api/user/setup Complete user setup with health data and scoring

Initialize user profile, process health metrics, calculate health score, and generate AI recommendations. This endpoint completes the user setup flow. Use after onboarding to finalize the user account with initial health data.

FieldTypeRequiredDescription
userobjectrequired
dataobject[]optional
onboardingSourcestringoptional
onboardingobjectoptional
PATCH /api/user/timezone Save device IANA timezone for the current user

Stores the user device time zone in user_preferences (IANA name). Used for HealthKit "today" aggregation and timezone-aware schedules. Invalid zone names are rejected with 400.

FieldTypeRequiredDescription
timezonestringrequiredIANA time zone identifier from the device (e.g. from Intl / RN)