curl --request POST \
--url https://sandbox.rx.tera.health/v1/patient/ai-coach/conversations/{conversation_id}/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"body": "What can I eat tonight instead of salmon?"
}
'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({body: JSON.stringify('What can I eat tonight instead of salmon?')})
};
fetch('https://sandbox.rx.tera.health/v1/patient/ai-coach/conversations/{conversation_id}/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://sandbox.rx.tera.health/v1/patient/ai-coach/conversations/{conversation_id}/messages"
payload = { "body": "What can I eat tonight instead of salmon?" }
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Message the AI Coach
Stores the patient’s message and starts the AI Coach’s reply. The response has the stored message and the reply in
pending; get the reply with GET /v1/patient/ai-coach/messages/{message_id}/reply, by polling or as a stream.
The AI Coach is not emergency care. Show the 911 and 988 guidance next to the message box. When the AI Coach escalates (a red-flag
symptom, a dosing or medication question, a new or severe side effect), the reply carries escalation:
on ai_only it is a clinical flag to the brand’s prescriber, on the coached plan a task for the coach.
When the AI Coach is paused for the plan, the reply is the plan’s holding message. Error codes:
daily_message_cap_reached (429), ai_unavailable (503).
Plans: AI + health and fitness coaches (ai_health_fitness), AI only (ai_only).
curl --request POST \
--url https://sandbox.rx.tera.health/v1/patient/ai-coach/conversations/{conversation_id}/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"body": "What can I eat tonight instead of salmon?"
}
'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({body: JSON.stringify('What can I eat tonight instead of salmon?')})
};
fetch('https://sandbox.rx.tera.health/v1/patient/ai-coach/conversations/{conversation_id}/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://sandbox.rx.tera.health/v1/patient/ai-coach/conversations/{conversation_id}/messages"
payload = { "body": "What can I eat tonight instead of salmon?" }
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Authorizations
A 15-minute token bound to one patient and one enrollment, issued by POST /v1/oauth/token with the
token-exchange grant. Treat it as opaque. When it expires, exchange a fresh assertion; there is no refresh token.
Headers
A unique key per logical request, for example a UUID. Retrying with the same key and the same body
within 24 hours returns the first response (with Idempotent-Replayed: true) instead of creating a duplicate.
The same key with a different body is refused with 422 idempotency_key_reused.
8 - 255Path Parameters
Body
1 - 4000"Nausea is better today. Can I swap dinner?"

