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.
/api/v1/help-desks/{helpDeskId}/agentsPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/agentsPath parameters
helpDeskIdstringrequired- Help desk id.
Body
application/jsonuserId- 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}'
{"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.
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/agents/{agentId}Path parameters
helpDeskIdstringrequired- Help desk id.
agentIdstringrequired- Agent id.
Body
application/jsondeskRole- 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}'
{"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`).
/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"
{"data": {"deleted": true},"meta": {"requestId": "req_…"}}
List teams#
The desk's teams, with their members.
/api/v1/help-desks/{helpDeskId}/teamsPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/teamsPath parameters
helpDeskIdstringrequired- Help desk id.
Body
application/jsonname- 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"}'
{"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.
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/teams/{teamId}Path parameters
helpDeskIdstringrequired- Help desk id.
teamIdstringrequired- team id.
Body
application/jsonname- 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"}'
{"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.
/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"
{"data": {"deleted": true,"effect": "deleted","message": "Deleted \"Billing\""},"meta": {"requestId": "req_…"}}
Get team members#
The agents on a team.
/api/v1/help-desks/{helpDeskId}/teams/{teamId}/membersPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/teams/{teamId}/membersPath parameters
helpDeskIdstringrequired- Help desk id.
teamIdstringrequired- Team id.
Body
application/jsonagentIds- 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…"]}'
{"data": {"teamId": "7b31…","agentIds": ["a1f0…","b2e1…"]},"meta": {"requestId": "req_…"}}
List custom fields#
Fields on conversations, contacts and companies.
/api/v1/help-desks/{helpDeskId}/custom-fieldsPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/custom-fieldsPath parameters
helpDeskIdstringrequired- Help desk id.
Body
application/jsonentity- 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"}]}'
{"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.
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/custom-fields/{fieldId}Path parameters
helpDeskIdstringrequired- Help desk id.
fieldIdstringrequired- custom field id.
Body
application/jsonentity- 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}'
{"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.
/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"
{"data": {"deleted": true,"effect": "deleted","message": "Deleted \"custom field\""},"meta": {"requestId": "req_…"}}
List brands#
The brands this desk answers under.
/api/v1/help-desks/{helpDeskId}/brandsPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/brandsPath parameters
helpDeskIdstringrequired- Help desk id.
Body
application/jsonname- 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"}'
{"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.
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/brands/{brandId}Path parameters
helpDeskIdstringrequired- Help desk id.
brandIdstringrequired- brand id.
Body
application/jsonname- 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}'
{"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`).
/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"
{"data": {"deleted": true,"effect": "deleted","message": "Deleted \"Acme Health\""},"meta": {"requestId": "req_…"}}
List schedules#
The desk's business hours.
/api/v1/help-desks/{helpDeskId}/schedulesPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/schedulesPath parameters
helpDeskIdstringrequired- Help desk id.
Body
application/jsonname- 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"}]}'
{"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.
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/schedules/{scheduleId}Path parameters
helpDeskIdstringrequired- Help desk id.
scheduleIdstringrequired- schedule id.
Body
application/jsonname- 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"}'
{"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.
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/sla-policiesPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/sla-policiesPath parameters
helpDeskIdstringrequired- Help desk id.
Body
application/jsonname- 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}]}'
{"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.
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/sla-policies/{policyId}Path parameters
helpDeskIdstringrequired- Help desk id.
policyIdstringrequired- SLA policy id.
Body
application/jsonname- 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}'
{"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.
/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"
{"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=`.
/api/v1/help-desks/{helpDeskId}/viewsPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/viewsPath parameters
helpDeskIdstringrequired- Help desk id.
Body
application/jsonname- 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"}'
{"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.
/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"
{"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`).
/api/v1/help-desks/{helpDeskId}/views/{viewId}Path parameters
helpDeskIdstringrequired- Help desk id.
viewIdstringrequired- view id.
Body
application/jsonname- 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"}'
{"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).
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/routing-rulesPath 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"
{"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.
/api/v1/help-desks/{helpDeskId}/routing-rulesPath parameters
helpDeskIdstringrequired- Help desk id.
Body
application/jsonname- 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"}]}}'
{"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.
/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"
{"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.
/api/v1/help-desks/{helpDeskId}/routing-rules/{ruleId}Path parameters
helpDeskIdstringrequired- Help desk id.
ruleIdstringrequired- routing rule id.
Body
application/jsonname- 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}'
{"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.
/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"
{"data": {"deleted": true,"effect": "deleted","message": "Deleted \"Invoices to billing\""},"meta": {"requestId": "req_…"}}