Help desk configuration

The people, teams, tags, fields, brands, hours, SLAs, views and routing behind a desk.

Everything that shapes how a desk works, as resources you can read and manage. Reading needs help_desk:read. Changing configuration needs help_desk:configure, and the key's owner must also be a lead or admin on the desk, or not staff it at all (an organization admin or the desk's creator). A plain agent's key is refused with insufficient_desk_role.

Updates are partial: a PATCH changes the fields you send and keeps the rest. Lists inside a record, such as a schedule's intervals or a policy's targets, are replaced as a whole when sent.

Deleting configuration is honest about what depends on it. A brand that conversations were answered under, the desk's default schedule, or a team a routing rule still targets are refused with 409 and a details.reason naming the dependency, so the fix is clear. Every id you send must belong to the same desk; an id from anywhere else is a 422, and an id from anywhere else in the path is a 404.

List agents#

The desk's roster, with live presence and how many open conversations each agent holds.

GET/api/v1/help-desks/{helpDeskId}/agents

Path parameters

helpDeskIdstringrequired
Help desk id.

Responses

The agents.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/agents" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"agents": [
{
"id": "a1f0…",
"userId": "5d2c…",
"deskRole": "agent",
"displayName": "Sam Rivera",
"publicAlias": "Sam from Support",
"avatarUrl": null,
"signature": null,
"maxOpen": 5,
"skills": [
"billing"
],
"locales": [
"en"
],
"presence": "online",
"openCount": 3
}
]
},
"meta": {
"requestId": "req_…"
}
}

Add an agent#

Staff the desk with a member of its organization. Re-adding someone who was removed restores their agent record and history. Only a desk admin can add another admin.

POST/api/v1/help-desks/{helpDeskId}/agents

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
userId
string
required
deskRole
agent | lead | admin
maxOpen
number

Responses

The agent.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/agents" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "5d2c…",
"deskRole": "agent",
"maxOpen": 5
}'
Response201
{
"data": {
"id": "a1f0…",
"userId": "5d2c…",
"deskRole": "agent",
"displayName": "Sam Rivera",
"publicAlias": "Sam from Support",
"avatarUrl": null,
"signature": null,
"maxOpen": 5,
"skills": [
"billing"
],
"locales": [
"en"
],
"presence": "online",
"openCount": 3
},
"meta": {
"requestId": "req_…"
}
}

Get an agent#

One agent on the desk.

GET/api/v1/help-desks/{helpDeskId}/agents/{agentId}

Path parameters

helpDeskIdstringrequired
Help desk id.
agentIdstringrequired
Agent id.

Responses

The agent.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/agents/{agentId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "a1f0…",
"userId": "5d2c…",
"deskRole": "agent",
"displayName": "Sam Rivera",
"publicAlias": "Sam from Support",
"avatarUrl": null,
"signature": null,
"maxOpen": 5,
"skills": [
"billing"
],
"locales": [
"en"
],
"presence": "online",
"openCount": 3
},
"meta": {
"requestId": "req_…"
}
}

Update an agent#

An agent may change how they present themselves (display name, public alias, avatar, signature) with their own key, which needs only `help_desk:respond`. Send `null` to clear one of those and fall back to the user's profile. Changing anyone else, or role, capacity, skills and locales, needs `help_desk:configure` and a lead or admin; granting or removing the admin role needs an admin; and nobody changes their own role. A desk always keeps one admin.

PATCH/api/v1/help-desks/{helpDeskId}/agents/{agentId}

Path parameters

helpDeskIdstringrequired
Help desk id.
agentIdstringrequired
Agent id.

Body

application/json
deskRole
agent | lead | admin
displayName
string | null
publicAlias
string | null
avatarUrl
string | null
signature
string | null
maxOpen
number
skills
string[]
locales
string[]

Responses

The updated agent.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/agents/{agentId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"skills": [
"billing",
"refunds"
],
"maxOpen": 6
}'
Response200
{
"data": {
"id": "a1f0…",
"userId": "5d2c…",
"deskRole": "agent",
"displayName": "Sam Rivera",
"publicAlias": "Sam from Support",
"avatarUrl": null,
"signature": null,
"maxOpen": 5,
"skills": [
"billing"
],
"locales": [
"en"
],
"presence": "online",
"openCount": 3
},
"meta": {
"requestId": "req_…"
}
}

Remove an agent#

Take someone off the desk. Their past replies stay attributed to them, and they leave every team they were on. The last admin cannot be removed (409 `last_admin`).

DELETE/api/v1/help-desks/{helpDeskId}/agents/{agentId}

Path parameters

helpDeskIdstringrequired
Help desk id.
agentIdstringrequired
Agent id.

Responses

Removed.

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

List teams#

The desk's teams, with their members.

GET/api/v1/help-desks/{helpDeskId}/teams

Path parameters

helpDeskIdstringrequired
Help desk id.

Responses

The teams.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/teams" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"teams": [
{
"id": "7b31…",
"name": "Billing",
"description": "Refunds and invoices",
"color": "#2563eb",
"scheduleId": "c0de…",
"memberCount": 4,
"memberIds": [
"a1f0…"
]
}
]
},
"meta": {
"requestId": "req_…"
}
}

Create a team#

A group of agents that conversations, views and routing rules can point at. A team can work its own business hours.

POST/api/v1/help-desks/{helpDeskId}/teams

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
name
string
required
description
string | null
color
string | null (hex)
scheduleId
string | null

Responses

The created team.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/teams" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Billing",
"color": "#2563eb"
}'
Response201
{
"data": {
"id": "7b31…",
"name": "Billing",
"description": "Refunds and invoices",
"color": "#2563eb",
"scheduleId": "c0de…",
"memberCount": 4,
"memberIds": [
"a1f0…"
]
},
"meta": {
"requestId": "req_…"
}
}

Get a team#

One team.

GET/api/v1/help-desks/{helpDeskId}/teams/{teamId}

Path parameters

helpDeskIdstringrequired
Help desk id.
teamIdstringrequired
team id.

Responses

The team.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/teams/{teamId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "7b31…",
"name": "Billing",
"description": "Refunds and invoices",
"color": "#2563eb",
"scheduleId": "c0de…",
"memberCount": 4,
"memberIds": [
"a1f0…"
]
},
"meta": {
"requestId": "req_…"
}
}

Update a team#

Change a team. Send `scheduleId: null` to put it back on the desk's hours.

PATCH/api/v1/help-desks/{helpDeskId}/teams/{teamId}

Path parameters

helpDeskIdstringrequired
Help desk id.
teamIdstringrequired
team id.

Body

application/json
name
string
description
string | null
color
string | null (hex)
scheduleId
string | null

Responses

The updated team.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/teams/{teamId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"description": "Refunds and invoices"
}'
Response200
{
"data": {
"id": "7b31…",
"name": "Billing",
"description": "Refunds and invoices",
"color": "#2563eb",
"scheduleId": "c0de…",
"memberCount": 4,
"memberIds": [
"a1f0…"
]
},
"meta": {
"requestId": "req_…"
}
}

Delete a team#

Delete a team. Its conversations are kept and no longer belong to a team. Refused while a view, macro or routing rule still points at it.

DELETE/api/v1/help-desks/{helpDeskId}/teams/{teamId}

Path parameters

helpDeskIdstringrequired
Help desk id.
teamIdstringrequired
team id.

Responses

Deleted. A refusal is 409 with `details.reason` naming what still depends on it.

curl -X DELETE "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/teams/{teamId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true,
"effect": "deleted",
"message": "Deleted \"Billing\""
},
"meta": {
"requestId": "req_…"
}
}

Get team members#

The agents on a team.

GET/api/v1/help-desks/{helpDeskId}/teams/{teamId}/members

Path parameters

helpDeskIdstringrequired
Help desk id.
teamIdstringrequired
Team id.

Responses

The members.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/teams/{teamId}/members" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"teamId": "7b31…",
"agentIds": [
"a1f0…"
]
},
"meta": {
"requestId": "req_…"
}
}

Set team members#

Replace a team's membership with exactly this set. Every id must be an agent on the desk, or nothing is changed.

PUT/api/v1/help-desks/{helpDeskId}/teams/{teamId}/members

Path parameters

helpDeskIdstringrequired
Help desk id.
teamIdstringrequired
Team id.

Body

application/json
agentIds
string[]
required

Responses

The membership now.

curl -X PUT "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/teams/{teamId}/members" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentIds": [
"a1f0…",
"b2e1…"
]
}'
Response200
{
"data": {
"teamId": "7b31…",
"agentIds": [
"a1f0…",
"b2e1…"
]
},
"meta": {
"requestId": "req_…"
}
}

List tags#

The desk's tags, most used first.

GET/api/v1/help-desks/{helpDeskId}/tags

Path parameters

helpDeskIdstringrequired
Help desk id.

Responses

The tags.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/tags" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"tags": [
{
"id": "e9a2…",
"name": "refund",
"color": "#16a34a",
"description": null,
"isAiManaged": false,
"usageCount": 12
}
]
},
"meta": {
"requestId": "req_…"
}
}

Create a tag#

Any agent on the desk may create a tag (`help_desk:respond`). Names are stored in lower case, so a second tag differing only in case is a 409.

POST/api/v1/help-desks/{helpDeskId}/tags

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
name
string
required
color
string | null (hex)
description
string | null

Responses

The created tag.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/tags" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "refund",
"color": "#16a34a"
}'
Response201
{
"data": {
"id": "e9a2…",
"name": "refund",
"color": "#16a34a",
"description": null,
"isAiManaged": false,
"usageCount": 12
},
"meta": {
"requestId": "req_…"
}
}

Get a tag#

One tag.

GET/api/v1/help-desks/{helpDeskId}/tags/{tagId}

Path parameters

helpDeskIdstringrequired
Help desk id.
tagIdstringrequired
tag id.

Responses

The tag.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/tags/{tagId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "e9a2…",
"name": "refund",
"color": "#16a34a",
"description": null,
"isAiManaged": false,
"usageCount": 12
},
"meta": {
"requestId": "req_…"
}
}

Update a tag#

Rename or recolour a tag. A lead or admin decision.

PATCH/api/v1/help-desks/{helpDeskId}/tags/{tagId}

Path parameters

helpDeskIdstringrequired
Help desk id.
tagIdstringrequired
tag id.

Body

application/json
name
string
color
string | null (hex)
description
string | null

Responses

The updated tag.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/tags/{tagId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"description": "Money back requests"
}'
Response200
{
"data": {
"id": "e9a2…",
"name": "refund",
"color": "#16a34a",
"description": null,
"isAiManaged": false,
"usageCount": 12
},
"meta": {
"requestId": "req_…"
}
}

Delete a tag#

Retire a tag. Conversations that carry it keep it, so past reports read the same; it stops being offered, and its name is free to reuse.

DELETE/api/v1/help-desks/{helpDeskId}/tags/{tagId}

Path parameters

helpDeskIdstringrequired
Help desk id.
tagIdstringrequired
tag id.

Responses

Deleted. A refusal is 409 with `details.reason` naming what still depends on it.

curl -X DELETE "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/tags/{tagId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true,
"effect": "deleted",
"message": "Deleted \"refund\""
},
"meta": {
"requestId": "req_…"
}
}

List custom fields#

Fields on conversations, contacts and companies.

GET/api/v1/help-desks/{helpDeskId}/custom-fields

Path parameters

helpDeskIdstringrequired
Help desk id.

Query parameters

entitystring
conversation, contact or company.

Responses

The custom fields.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/custom-fields" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"fields": [
{
"id": "f00d…",
"entity": "conversation",
"fieldKey": "region",
"label": "Region",
"description": null,
"fieldType": "select",
"options": [
{
"value": "emea",
"label": "EMEA"
},
{
"value": "amer",
"label": "Americas"
}
],
"isRequired": false,
"visibleToContact": false,
"editableByContact": false,
"position": 0
}
]
},
"meta": {
"requestId": "req_…"
}
}

Create a custom field#

A field whose values are set through the record's `customFields`, and that filters can match on by `fieldKey`. Keys are letters, digits and underscores. Select fields need options. A field the contact can edit must be visible to them.

POST/api/v1/help-desks/{helpDeskId}/custom-fields

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
entity
conversation | contact | company
required
fieldKey
string
required
label
string
required
description
string | null
fieldType
string
required
options
{ value, label, color? }[]
isRequired
boolean
visibleToContact
boolean
editableByContact
boolean
position
number

Responses

The created custom field.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/custom-fields" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"entity": "conversation",
"fieldKey": "region",
"label": "Region",
"fieldType": "select",
"options": [
{
"value": "emea",
"label": "EMEA"
},
{
"value": "amer",
"label": "Americas"
}
]
}'
Response201
{
"data": {
"id": "f00d…",
"entity": "conversation",
"fieldKey": "region",
"label": "Region",
"description": null,
"fieldType": "select",
"options": [
{
"value": "emea",
"label": "EMEA"
},
{
"value": "amer",
"label": "Americas"
}
],
"isRequired": false,
"visibleToContact": false,
"editableByContact": false,
"position": 0
},
"meta": {
"requestId": "req_…"
}
}

Get a custom field#

One custom field.

GET/api/v1/help-desks/{helpDeskId}/custom-fields/{fieldId}

Path parameters

helpDeskIdstringrequired
Help desk id.
fieldIdstringrequired
custom field id.

Responses

The custom field.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/custom-fields/{fieldId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "f00d…",
"entity": "conversation",
"fieldKey": "region",
"label": "Region",
"description": null,
"fieldType": "select",
"options": [
{
"value": "emea",
"label": "EMEA"
},
{
"value": "amer",
"label": "Americas"
}
],
"isRequired": false,
"visibleToContact": false,
"editableByContact": false,
"position": 0
},
"meta": {
"requestId": "req_…"
}
}

Update a custom field#

Change a field's label, type, options or visibility. `entity` and `fieldKey` cannot change once created.

PATCH/api/v1/help-desks/{helpDeskId}/custom-fields/{fieldId}

Path parameters

helpDeskIdstringrequired
Help desk id.
fieldIdstringrequired
custom field id.

Body

application/json
entity
conversation | contact | company
fieldKey
string
label
string
description
string | null
fieldType
string
options
{ value, label, color? }[]
isRequired
boolean
visibleToContact
boolean
editableByContact
boolean
position
number

Responses

The updated custom field.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/custom-fields/{fieldId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "Sales region",
"isRequired": true
}'
Response200
{
"data": {
"id": "f00d…",
"entity": "conversation",
"fieldKey": "region",
"label": "Region",
"description": null,
"fieldType": "select",
"options": [
{
"value": "emea",
"label": "EMEA"
},
{
"value": "amer",
"label": "Americas"
}
],
"isRequired": false,
"visibleToContact": false,
"editableByContact": false,
"position": 0
},
"meta": {
"requestId": "req_…"
}
}

Delete a custom field#

Delete a field. Refused while a view, trigger, automation, SLA policy or routing rule filters on it, because those would silently stop matching.

DELETE/api/v1/help-desks/{helpDeskId}/custom-fields/{fieldId}

Path parameters

helpDeskIdstringrequired
Help desk id.
fieldIdstringrequired
custom field id.

Responses

Deleted. A refusal is 409 with `details.reason` naming what still depends on it.

curl -X DELETE "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/custom-fields/{fieldId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true,
"effect": "deleted",
"message": "Deleted \"custom field\""
},
"meta": {
"requestId": "req_…"
}
}

List brands#

The brands this desk answers under.

GET/api/v1/help-desks/{helpDeskId}/brands

Path parameters

helpDeskIdstringrequired
Help desk id.

Responses

The brands.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/brands" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"brands": [
{
"id": "b7a9…",
"name": "Acme Health",
"slug": "acme-health",
"logoUrl": null,
"faviconUrl": null,
"primaryColor": "#0f766e",
"supportEmail": "help@acme.example",
"helpCenterHost": null,
"helpCenterEnabled": false,
"isDefault": false
}
]
},
"meta": {
"requestId": "req_…"
}
}

Create a brand#

A name, look and support address. The slug comes from the name unless you send one, and appears in help center links. Setting `isDefault` also makes it the desk's default brand for new conversations.

POST/api/v1/help-desks/{helpDeskId}/brands

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
name
string
required
slug
string
logoUrl
string | null
faviconUrl
string | null
primaryColor
string | null (hex)
supportEmail
string | null
helpCenterHost
string | null
helpCenterEnabled
boolean
isDefault
boolean

Responses

The created brand.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/brands" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Health",
"supportEmail": "help@acme.example",
"primaryColor": "#0f766e"
}'
Response201
{
"data": {
"id": "b7a9…",
"name": "Acme Health",
"slug": "acme-health",
"logoUrl": null,
"faviconUrl": null,
"primaryColor": "#0f766e",
"supportEmail": "help@acme.example",
"helpCenterHost": null,
"helpCenterEnabled": false,
"isDefault": false
},
"meta": {
"requestId": "req_…"
}
}

Get a brand#

One brand.

GET/api/v1/help-desks/{helpDeskId}/brands/{brandId}

Path parameters

helpDeskIdstringrequired
Help desk id.
brandIdstringrequired
brand id.

Responses

The brand.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/brands/{brandId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "b7a9…",
"name": "Acme Health",
"slug": "acme-health",
"logoUrl": null,
"faviconUrl": null,
"primaryColor": "#0f766e",
"supportEmail": "help@acme.example",
"helpCenterHost": null,
"helpCenterEnabled": false,
"isDefault": false
},
"meta": {
"requestId": "req_…"
}
}

Update a brand#

Change a brand. A rename keeps the slug so existing links keep working. `isDefault: true` makes it the desk's default brand. The default cannot be unset directly (422 `default_required`): make another brand the default instead.

PATCH/api/v1/help-desks/{helpDeskId}/brands/{brandId}

Path parameters

helpDeskIdstringrequired
Help desk id.
brandIdstringrequired
brand id.

Body

application/json
name
string
slug
string
logoUrl
string | null
faviconUrl
string | null
primaryColor
string | null (hex)
supportEmail
string | null
helpCenterHost
string | null
helpCenterEnabled
boolean
isDefault
boolean

Responses

The updated brand.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/brands/{brandId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"isDefault": true
}'
Response200
{
"data": {
"id": "b7a9…",
"name": "Acme Health",
"slug": "acme-health",
"logoUrl": null,
"faviconUrl": null,
"primaryColor": "#0f766e",
"supportEmail": "help@acme.example",
"helpCenterHost": null,
"helpCenterEnabled": false,
"isDefault": false
},
"meta": {
"requestId": "req_…"
}
}

Delete a brand#

Delete a brand. Refused while it is the desk's default (`is_default`), the desk's only brand (`last_brand`), or conversations were answered under it (`has_conversations`).

DELETE/api/v1/help-desks/{helpDeskId}/brands/{brandId}

Path parameters

helpDeskIdstringrequired
Help desk id.
brandIdstringrequired
brand id.

Responses

Deleted. A refusal is 409 with `details.reason` naming what still depends on it.

curl -X DELETE "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/brands/{brandId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true,
"effect": "deleted",
"message": "Deleted \"Acme Health\""
},
"meta": {
"requestId": "req_…"
}
}

List schedules#

The desk's business hours.

GET/api/v1/help-desks/{helpDeskId}/schedules

Path parameters

helpDeskIdstringrequired
Help desk id.

Responses

The schedules.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/schedules" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"schedules": [
{
"id": "c0de…",
"name": "EMEA hours",
"timeZone": "Europe/London",
"isDefault": false,
"intervals": [
{
"id": "…",
"dayOfWeek": 1,
"startMinute": 480,
"endMinute": 1080
}
],
"holidays": [
{
"id": "…",
"name": "Boxing Day",
"startDate": "2026-12-26",
"endDate": "2026-12-26"
}
]
}
]
},
"meta": {
"requestId": "req_…"
}
}

Create a schedule#

Weekly open intervals (minutes from midnight, `dayOfWeek` 0 for Sunday) and holidays, in an IANA time zone. SLA targets marked business-hours-only count time only while the schedule is open. Setting `isDefault` also makes it the desk's default schedule.

POST/api/v1/help-desks/{helpDeskId}/schedules

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
name
string
required
timeZone
string (IANA)
required
isDefault
boolean
intervals
{ dayOfWeek, startMinute, endMinute }[]
required
holidays
{ name, startDate, endDate }[] (YYYY-MM-DD)

Responses

The created schedule.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/schedules" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "EMEA hours",
"timeZone": "Europe/London",
"intervals": [
{
"dayOfWeek": 1,
"startMinute": 480,
"endMinute": 1080
}
],
"holidays": [
{
"name": "Boxing Day",
"startDate": "2026-12-26",
"endDate": "2026-12-26"
}
]
}'
Response201
{
"data": {
"id": "c0de…",
"name": "EMEA hours",
"timeZone": "Europe/London",
"isDefault": false,
"intervals": [
{
"id": "…",
"dayOfWeek": 1,
"startMinute": 480,
"endMinute": 1080
}
],
"holidays": [
{
"id": "…",
"name": "Boxing Day",
"startDate": "2026-12-26",
"endDate": "2026-12-26"
}
]
},
"meta": {
"requestId": "req_…"
}
}

Get a schedule#

One schedule.

GET/api/v1/help-desks/{helpDeskId}/schedules/{scheduleId}

Path parameters

helpDeskIdstringrequired
Help desk id.
scheduleIdstringrequired
schedule id.

Responses

The schedule.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/schedules/{scheduleId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "c0de…",
"name": "EMEA hours",
"timeZone": "Europe/London",
"isDefault": false,
"intervals": [
{
"id": "…",
"dayOfWeek": 1,
"startMinute": 480,
"endMinute": 1080
}
],
"holidays": [
{
"id": "…",
"name": "Boxing Day",
"startDate": "2026-12-26",
"endDate": "2026-12-26"
}
]
},
"meta": {
"requestId": "req_…"
}
}

Update a schedule#

Change a schedule. `intervals` and `holidays` each replace the whole list when sent. `isDefault: true` makes it the desk's default schedule. The default cannot be unset directly (422 `default_required`): make another schedule the default instead.

PATCH/api/v1/help-desks/{helpDeskId}/schedules/{scheduleId}

Path parameters

helpDeskIdstringrequired
Help desk id.
scheduleIdstringrequired
schedule id.

Body

application/json
name
string
timeZone
string (IANA)
isDefault
boolean
intervals
{ dayOfWeek, startMinute, endMinute }[]
holidays
{ name, startDate, endDate }[] (YYYY-MM-DD)

Responses

The updated schedule.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/schedules/{scheduleId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "EMEA support hours"
}'
Response200
{
"data": {
"id": "c0de…",
"name": "EMEA hours",
"timeZone": "Europe/London",
"isDefault": false,
"intervals": [
{
"id": "…",
"dayOfWeek": 1,
"startMinute": 480,
"endMinute": 1080
}
],
"holidays": [
{
"id": "…",
"name": "Boxing Day",
"startDate": "2026-12-26",
"endDate": "2026-12-26"
}
]
},
"meta": {
"requestId": "req_…"
}
}

Delete a schedule#

Delete a schedule. Refused while it is the desk's default, or a team or widget still works on it.

DELETE/api/v1/help-desks/{helpDeskId}/schedules/{scheduleId}

Path parameters

helpDeskIdstringrequired
Help desk id.
scheduleIdstringrequired
schedule id.

Responses

Deleted. A refusal is 409 with `details.reason` naming what still depends on it.

curl -X DELETE "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/schedules/{scheduleId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true,
"effect": "deleted",
"message": "Deleted \"EMEA hours\""
},
"meta": {
"requestId": "req_…"
}
}

List SLA policies#

The desk's SLA policies, in the order they are tried.

GET/api/v1/help-desks/{helpDeskId}/sla-policies

Path parameters

helpDeskIdstringrequired
Help desk id.

Responses

The SLA policies.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/sla-policies" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"policies": [
{
"id": "5a1a…",
"name": "VIP",
"description": null,
"conditions": {
"op": "and",
"rules": [
{
"field": "priority",
"op": "eq",
"value": "urgent"
}
]
},
"position": 1,
"isActive": true,
"targets": [
{
"id": "…",
"priority": "urgent",
"metric": "first_reply",
"targetMinutes": 15,
"businessHoursOnly": false
}
]
}
]
},
"meta": {
"requestId": "req_…"
}
}

Create a SLA policy#

Reply and resolution targets per priority. A new conversation gets the first policy, in `position` order, whose conditions match it. One target per priority and metric. Conditions use the same filter grammar as conversation listing, and are checked when saved: a filter that could never run is refused with 422.

POST/api/v1/help-desks/{helpDeskId}/sla-policies

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
name
string
required
description
string | null
conditions
FilterGroup | null
position
number
targets
{ priority, metric, targetMinutes, businessHoursOnly }[]
required

Responses

The created SLA policy.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/sla-policies" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "VIP",
"conditions": {
"op": "and",
"rules": [
{
"field": "priority",
"op": "eq",
"value": "urgent"
}
]
},
"targets": [
{
"priority": "urgent",
"metric": "first_reply",
"targetMinutes": 15,
"businessHoursOnly": false
}
]
}'
Response201
{
"data": {
"id": "5a1a…",
"name": "VIP",
"description": null,
"conditions": {
"op": "and",
"rules": [
{
"field": "priority",
"op": "eq",
"value": "urgent"
}
]
},
"position": 1,
"isActive": true,
"targets": [
{
"id": "…",
"priority": "urgent",
"metric": "first_reply",
"targetMinutes": 15,
"businessHoursOnly": false
}
]
},
"meta": {
"requestId": "req_…"
}
}

Get a SLA policy#

One SLA policy.

GET/api/v1/help-desks/{helpDeskId}/sla-policies/{policyId}

Path parameters

helpDeskIdstringrequired
Help desk id.
policyIdstringrequired
SLA policy id.

Responses

The SLA policy.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/sla-policies/{policyId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "5a1a…",
"name": "VIP",
"description": null,
"conditions": {
"op": "and",
"rules": [
{
"field": "priority",
"op": "eq",
"value": "urgent"
}
]
},
"position": 1,
"isActive": true,
"targets": [
{
"id": "…",
"priority": "urgent",
"metric": "first_reply",
"targetMinutes": 15,
"businessHoursOnly": false
}
]
},
"meta": {
"requestId": "req_…"
}
}

Update a SLA policy#

Change a policy. `targets` replaces the whole set when sent. Conversations already running keep the targets they started with.

PATCH/api/v1/help-desks/{helpDeskId}/sla-policies/{policyId}

Path parameters

helpDeskIdstringrequired
Help desk id.
policyIdstringrequired
SLA policy id.

Body

application/json
name
string
description
string | null
conditions
FilterGroup | null
position
number
targets
{ priority, metric, targetMinutes, businessHoursOnly }[]

Responses

The updated SLA policy.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/sla-policies/{policyId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"position": 0
}'
Response200
{
"data": {
"id": "5a1a…",
"name": "VIP",
"description": null,
"conditions": {
"op": "and",
"rules": [
{
"field": "priority",
"op": "eq",
"value": "urgent"
}
]
},
"position": 1,
"isActive": true,
"targets": [
{
"id": "…",
"priority": "urgent",
"metric": "first_reply",
"targetMinutes": 15,
"businessHoursOnly": false
}
]
},
"meta": {
"requestId": "req_…"
}
}

Delete a SLA policy#

Delete a policy. Refused while it is the desk's default.

DELETE/api/v1/help-desks/{helpDeskId}/sla-policies/{policyId}

Path parameters

helpDeskIdstringrequired
Help desk id.
policyIdstringrequired
SLA policy id.

Responses

Deleted. A refusal is 409 with `details.reason` naming what still depends on it.

curl -X DELETE "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/sla-policies/{policyId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true,
"effect": "deleted",
"message": "Deleted \"VIP\""
},
"meta": {
"requestId": "req_…"
}
}

List views#

The views the key's owner would see: shared views, their own personal views, and views of teams they are on. List conversations through one with `GET /conversations?viewId=`.

GET/api/v1/help-desks/{helpDeskId}/views

Path parameters

helpDeskIdstringrequired
Help desk id.

Query parameters

countsboolean
Include how many conversations each view matches.

Responses

The views.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/views" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"views": [
{
"id": "9e1e…",
"name": "EMEA queue",
"description": null,
"icon": null,
"scope": "shared",
"ownerAgentId": null,
"teamId": null,
"filter": {
"op": "and",
"rules": [
{
"field": "customField",
"key": "region",
"op": "eq",
"value": "emea"
}
]
},
"sortField": "createdAt",
"sortDirection": "asc",
"columns": null,
"position": 100,
"isSystem": false,
"systemKey": null
}
]
},
"meta": {
"requestId": "req_…"
}
}

Create a view#

A saved conversation filter. A `personal` view belongs to the key's owner, who must be an agent on the desk, and needs only `help_desk:respond`. `shared` and `team` views change what other people see and need `help_desk:configure` and a lead or admin. Conditions use the same filter grammar as conversation listing, and are checked when saved: a filter that could never run is refused with 422.

POST/api/v1/help-desks/{helpDeskId}/views

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
name
string
required
description
string | null
icon
string | null
scope
personal | team | shared
required
teamId
string (team views)
filter
FilterGroup
required
sortField
string
sortDirection
asc | desc
columns
string[] | null
position
number

Responses

The created view.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/views" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "EMEA queue",
"scope": "shared",
"filter": {
"op": "and",
"rules": [
{
"field": "customField",
"key": "region",
"op": "eq",
"value": "emea"
}
]
},
"sortField": "createdAt",
"sortDirection": "asc"
}'
Response201
{
"data": {
"id": "9e1e…",
"name": "EMEA queue",
"description": null,
"icon": null,
"scope": "shared",
"ownerAgentId": null,
"teamId": null,
"filter": {
"op": "and",
"rules": [
{
"field": "customField",
"key": "region",
"op": "eq",
"value": "emea"
}
]
},
"sortField": "createdAt",
"sortDirection": "asc",
"columns": null,
"position": 100,
"isSystem": false,
"systemKey": null
},
"meta": {
"requestId": "req_…"
}
}

Get a view#

One view.

GET/api/v1/help-desks/{helpDeskId}/views/{viewId}

Path parameters

helpDeskIdstringrequired
Help desk id.
viewIdstringrequired
view id.

Responses

The view.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/views/{viewId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "9e1e…",
"name": "EMEA queue",
"description": null,
"icon": null,
"scope": "shared",
"ownerAgentId": null,
"teamId": null,
"filter": {
"op": "and",
"rules": [
{
"field": "customField",
"key": "region",
"op": "eq",
"value": "emea"
}
]
},
"sortField": "createdAt",
"sortDirection": "asc",
"columns": null,
"position": 100,
"isSystem": false,
"systemKey": null
},
"meta": {
"requestId": "req_…"
}
}

Update a view#

Change a view. Someone else's personal view is not visible and reads as 404. The desk's built-in views can be reordered with `position` but not otherwise edited, columns included (409 `system_view`).

PATCH/api/v1/help-desks/{helpDeskId}/views/{viewId}

Path parameters

helpDeskIdstringrequired
Help desk id.
viewIdstringrequired
view id.

Body

application/json
name
string
description
string | null
icon
string | null
scope
personal | team | shared
teamId
string (team views)
filter
FilterGroup
sortField
string
sortDirection
asc | desc
columns
string[] | null
position
number

Responses

The updated view.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/views/{viewId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "EMEA first"
}'
Response200
{
"data": {
"id": "9e1e…",
"name": "EMEA queue",
"description": null,
"icon": null,
"scope": "shared",
"ownerAgentId": null,
"teamId": null,
"filter": {
"op": "and",
"rules": [
{
"field": "customField",
"key": "region",
"op": "eq",
"value": "emea"
}
]
},
"sortField": "createdAt",
"sortDirection": "asc",
"columns": null,
"position": 100,
"isSystem": false,
"systemKey": null
},
"meta": {
"requestId": "req_…"
}
}

Delete a view#

Delete a view. Built-in views cannot be deleted (409).

DELETE/api/v1/help-desks/{helpDeskId}/views/{viewId}

Path parameters

helpDeskIdstringrequired
Help desk id.
viewIdstringrequired
view id.

Responses

Deleted. A refusal is 409 with `details.reason` naming what still depends on it.

curl -X DELETE "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/views/{viewId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true,
"effect": "deleted",
"message": "Deleted \"EMEA queue\""
},
"meta": {
"requestId": "req_…"
}
}

List routing rules#

How new conversations are assigned, in the order rules are tried.

GET/api/v1/help-desks/{helpDeskId}/routing-rules

Path parameters

helpDeskIdstringrequired
Help desk id.

Responses

The routing rules.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/routing-rules" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"rules": [
{
"id": "4f4f…",
"name": "Invoices to billing",
"conditions": {
"op": "and",
"rules": [
{
"field": "subject",
"op": "contains",
"value": "invoice"
}
]
},
"mode": "skill_based",
"targetTeamId": "7b31…",
"requiredSkills": [
"billing"
],
"assignWhenAway": false,
"position": 10,
"isEnabled": true
}
]
},
"meta": {
"requestId": "req_…"
}
}

Create a routing rule#

The first rule, in `position` order, whose conditions match a new conversation picks its assignee: `manual` leaves it unassigned, `round_robin` and `load_balanced` spread it, `skill_based` needs `requiredSkills`, and `language` matches the conversation's locale. `targetTeamId` limits the choice to one team. Conditions use the same filter grammar as conversation listing, and are checked when saved: a filter that could never run is refused with 422.

POST/api/v1/help-desks/{helpDeskId}/routing-rules

Path parameters

helpDeskIdstringrequired
Help desk id.

Body

application/json
name
string
required
conditions
FilterGroup | null
mode
manual | round_robin | load_balanced | skill_based | language
required
targetTeamId
string | null
requiredSkills
string[]
assignWhenAway
boolean
position
number
isEnabled
boolean (switched off, a rule stays listed and never runs)

Responses

The created routing rule.

curl -X POST "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/routing-rules" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Invoices to billing",
"mode": "skill_based",
"requiredSkills": [
"billing"
],
"targetTeamId": "7b31…",
"conditions": {
"op": "and",
"rules": [
{
"field": "subject",
"op": "contains",
"value": "invoice"
}
]
}
}'
Response201
{
"data": {
"id": "4f4f…",
"name": "Invoices to billing",
"conditions": {
"op": "and",
"rules": [
{
"field": "subject",
"op": "contains",
"value": "invoice"
}
]
},
"mode": "skill_based",
"targetTeamId": "7b31…",
"requiredSkills": [
"billing"
],
"assignWhenAway": false,
"position": 10,
"isEnabled": true
},
"meta": {
"requestId": "req_…"
}
}

Get a routing rule#

One routing rule.

GET/api/v1/help-desks/{helpDeskId}/routing-rules/{ruleId}

Path parameters

helpDeskIdstringrequired
Help desk id.
ruleIdstringrequired
routing rule id.

Responses

The routing rule.

curl -X GET "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/routing-rules/{ruleId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"id": "4f4f…",
"name": "Invoices to billing",
"conditions": {
"op": "and",
"rules": [
{
"field": "subject",
"op": "contains",
"value": "invoice"
}
]
},
"mode": "skill_based",
"targetTeamId": "7b31…",
"requiredSkills": [
"billing"
],
"assignWhenAway": false,
"position": 10,
"isEnabled": true
},
"meta": {
"requestId": "req_…"
}
}

Update a routing rule#

Change a rule.

PATCH/api/v1/help-desks/{helpDeskId}/routing-rules/{ruleId}

Path parameters

helpDeskIdstringrequired
Help desk id.
ruleIdstringrequired
routing rule id.

Body

application/json
name
string
conditions
FilterGroup | null
mode
manual | round_robin | load_balanced | skill_based | language
targetTeamId
string | null
requiredSkills
string[]
assignWhenAway
boolean
position
number
isEnabled
boolean (switched off, a rule stays listed and never runs)

Responses

The updated routing rule.

curl -X PATCH "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/routing-rules/{ruleId}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"isEnabled": false
}'
Response200
{
"data": {
"id": "4f4f…",
"name": "Invoices to billing",
"conditions": {
"op": "and",
"rules": [
{
"field": "subject",
"op": "contains",
"value": "invoice"
}
]
},
"mode": "skill_based",
"targetTeamId": "7b31…",
"requiredSkills": [
"billing"
],
"assignWhenAway": false,
"position": 10,
"isEnabled": true
},
"meta": {
"requestId": "req_…"
}
}

Delete a routing rule#

Delete a rule.

DELETE/api/v1/help-desks/{helpDeskId}/routing-rules/{ruleId}

Path parameters

helpDeskIdstringrequired
Help desk id.
ruleIdstringrequired
routing rule id.

Responses

Deleted. A refusal is 409 with `details.reason` naming what still depends on it.

curl -X DELETE "https://voice.evryhealth.com/api/v1/help-desks/{helpDeskId}/routing-rules/{ruleId}" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"data": {
"deleted": true,
"effect": "deleted",
"message": "Deleted \"Invoices to billing\""
},
"meta": {
"requestId": "req_…"
}
}