Agents

Create, edit and version the thing that actually talks to people.

An agent is created from plain-language instructions, not from a prompt. The platform generates the prompt, versions it, and keeps the instructions as the thing a human edits, so an agent built through the API is the same object as one built in the product, editable in both.

engine names the product, never the vendor behind it: realtime is the managed engine, pipeline assembles your own transcription, language and speech models, and speech-to-speech runs a third-party realtime model with its own voice. Which models an engine runs on is configured in the product and is not part of this contract.

Every change is a version. A run, a call or an eval result names the version it was made against, which is what makes a result attributable months later.

Tags label agents and are not versioned. At most one of Production, Staging and Development marks the agent's environment; the rest are free-form, up to 20 per agent, 40 characters each, without commas. Tags that differ only in case are the same tag.

List agents#

Agents visible to the key's organization.

GET/api/v1/agents

Query parameters

searchstring
Match name, description or tag.
tagstring
Only agents carrying this tag. Comma-separate, or repeat, to match any of several.
pagenumber
Page number.
Default1
pageSizenumber
Up to 200.
Default50

Responses

A page of agents.

curl -X GET "https://voice.evryhealth.com/api/v1/agents" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"agents": [
{
"id": "44b1…",
"name": "Prescription follow-up",
"instructions": "Call the pharmacy and confirm the prescription is ready.",
"engine": "realtime",
"modality": "voice",
"voice": {
"name": "Mark",
"language": "en-US"
},
"currentVersion": 7
}
]
},
"meta": {
"requestId": "req_…",
"pagination": {
"nextCursor": null,
"limit": 50
}
}
}

Create an agent#

Describe what the agent should do; the prompt is generated from it before the agent is saved, the same way the product writes one, and the agent starts at version 1. Writing the prompt takes a few seconds to a minute. If it cannot be written the request fails with 503 and no agent is created; retrying is safe, and with an Idempotency-Key it cannot create the agent twice.

POST/api/v1/agents

Body

application/json
name
string
required
description
string
instructions
string
required
engine
realtime | pipeline | speech-to-speech
modality
voice | text | both
variables
{ name, description }[]
tags
string[]
isOrgShared
boolean

Responses

The created agent.

curl -X POST "https://voice.evryhealth.com/api/v1/agents" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Prescription follow-up",
"instructions": "Call the pharmacy, confirm the prescription is ready, and ask when it can be collected.",
"engine": "realtime",
"variables": [
{
"name": "patientName",
"description": "Who the prescription is for"
}
]
}'
Response201
{
"data": {
"id": "44b1…",
"name": "Prescription follow-up",
"engine": "realtime",
"currentVersion": 1
},
"meta": {
"requestId": "req_…"
}
}

Get an agent#

One agent, as it stands now.

GET/api/v1/agents/{agentId}

Path parameters

agentIdstringrequired
Agent id.

Responses

The agent.

curl -X GET "https://voice.evryhealth.com/api/v1/agents/{agentId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "44b1…",
"name": "Prescription follow-up"
},
"meta": {
"requestId": "req_…"
}
}

Update an agent#

Change any subset. Every change to the name, description, instructions, variables or engine is saved as a new version, which rollback can return to. Changing the instructions or the variables writes the prompt again from them, replacing any edits made to it in the product. `modality`, `isOrgShared` and `tags` are not versioned. If the prompt cannot be written the request fails with 503 and the agent is unchanged.

PATCH/api/v1/agents/{agentId}

Path parameters

agentIdstringrequired
Agent id.

Body

application/json
name
string
description
string
instructions
string
engine
realtime | pipeline | speech-to-speech
modality
voice | text | both
variables
{ name, description }[]
tags
string[]
isOrgShared
boolean

Responses

The updated agent.

curl -X PATCH "https://voice.evryhealth.com/api/v1/agents/{agentId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"instructions": "Confirm the prescription and ask when it can be collected."
}'
Response200
{
"data": {
"id": "44b1…",
"currentVersion": 8
},
"meta": {
"requestId": "req_…"
}
}

Tools on an agent#

The tools this agent may call.

GET/api/v1/agents/{agentId}/tools

Path parameters

agentIdstringrequired
Agent id.

Responses

The attached tools.

curl -X GET "https://voice.evryhealth.com/api/v1/agents/{agentId}/tools" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"tools": [
{
"id": "tool_9a1c…",
"name": "checkEligibility"
}
]
},
"meta": {
"requestId": "req_…"
}
}

Set an agent's tools#

Replaces the whole list. It is one field on the agent, so adding tools one at a time would mean whichever request lost the race lost its tool. Every id is checked against what the key can reach — an agent cannot be given a tool from another tenant.

PUT/api/v1/agents/{agentId}/tools

Path parameters

agentIdstringrequired
Agent id.

Body

application/json
toolIds
string[]
required

Responses

The attached tools.

curl -X PUT "https://voice.evryhealth.com/api/v1/agents/{agentId}/tools" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"toolIds": [
"tool_9a1c…",
"tool_41bb…"
]
}'
Response200
{
"data": {
"tools": [
{
"id": "tool_9a1c…",
"name": "checkEligibility"
}
]
},
"meta": {
"requestId": "req_…"
}
}

Agent voice#

The voice this agent speaks with.

GET/api/v1/agents/{agentId}/voice

Path parameters

agentIdstringrequired
Agent id.

Responses

The voice.

curl -X GET "https://voice.evryhealth.com/api/v1/agents/{agentId}/voice" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"voiceId": "87edb04c…",
"name": "Mark",
"language": "en-US"
},
"meta": {
"requestId": "req_…"
}
}

Set an agent's voice#

Pick a voice from `GET /api/v1/voices`. Only the managed and pipeline engines have a voice to set — a speech-to-speech engine's voice is part of the model it runs, and setting one there is refused rather than accepted and ignored.

PUT/api/v1/agents/{agentId}/voice

Path parameters

agentIdstringrequired
Agent id.

Body

application/json
voiceId
string
required
language
string (BCP47)

Responses

The voice now set.

curl -X PUT "https://voice.evryhealth.com/api/v1/agents/{agentId}/voice" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"voiceId": "87edb04c…",
"language": "en-US"
}'
Response200
{
"data": {
"voiceId": "87edb04c…",
"name": "Mark",
"language": "en-US"
},
"meta": {
"requestId": "req_…"
}
}

List voices#

Voices an agent can speak with, each with a language and a sample to listen to — which is the only honest way to choose one.

GET/api/v1/voices

Query parameters

languagestring
BCP47 or a bare language code. `es` matches every Spanish voice.

Responses

The voices.

curl -X GET "https://voice.evryhealth.com/api/v1/voices" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"voices": [
{
"id": "87edb04c…",
"name": "Mark",
"description": "Warm, measured, American English.",
"language": "en-US",
"previewUrl": "/api/v1/voices/87edb04c…/preview"
}
]
},
"meta": {
"requestId": "req_…"
}
}

Voice sample#

A spoken sample of one voice, as audio. Streamed through us rather than linked, so a voice picker never fetches from a host the customer has no relationship with.

GET/api/v1/voices/{voiceId}/preview

Path parameters

voiceIdstringrequired
Voice id.

Responses

Audio (audio/mpeg).

curl -X GET "https://voice.evryhealth.com/api/v1/voices/{voiceId}/preview" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"contentType": "audio/mpeg"
}

Version history#

Every change: what changed, who changed it, and why.

GET/api/v1/agents/{agentId}/versions

Path parameters

agentIdstringrequired
Agent id.

Query parameters

limitnumber
Up to 200.
Default50
offsetnumber
Skip this many.
Default0

Responses

The history.

curl -X GET "https://voice.evryhealth.com/api/v1/agents/{agentId}/versions" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"versions": [
{
"versionNumber": 8,
"changeType": "prompt_updated",
"changedByName": "Maria Alvarez",
"changedAt": "2026-09-15T13:02:00.000Z",
"isCurrent": true
}
],
"currentVersion": 8,
"total": 8
},
"meta": {
"requestId": "req_…"
}
}

Roll back#

Return to an earlier version. The rollback is recorded as a new version rather than rewinding history, so what the agent was doing on any given day stays answerable.

POST/api/v1/agents/{agentId}/rollback

Path parameters

agentIdstringrequired
Agent id.

Body

application/json
version
number
required
reason
string

Responses

The new version number.

curl -X POST "https://voice.evryhealth.com/api/v1/agents/{agentId}/rollback" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": 6,
"reason": "Version 7 asked for the date twice"
}'
Response200
{
"data": {
"version": 9
},
"meta": {
"requestId": "req_…"
}
}

Delete an agent#

Remove an agent. Calls it already made are unaffected.

DELETE/api/v1/agents/{agentId}

Path parameters

agentIdstringrequired
Agent id.

Responses

Deleted.

curl -X DELETE "https://voice.evryhealth.com/api/v1/agents/{agentId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true
},
"meta": {
"requestId": "req_…"
}
}