Phone Integration API
- Base URL:
https://phone-integration-api.sls.epilot.io - Full API Docs: https://docs.epilot.io/api/phone-integration
Usageโ
import { epilot } from '@epilot/sdk'
epilot.authorize(() => '<token>')
const { data } = await epilot.phoneIntegration.batchSearchCustomers(...)
Tree-shakeable importโ
import { getClient, authorize } from '@epilot/sdk/phone-integration'
const phoneIntegrationClient = getClient()
authorize(phoneIntegrationClient, () => '<token>')
const { data } = await phoneIntegrationClient.batchSearchCustomers(...)
Operationsโ
phone-integration
manager
getManagerStatuslistPhoneAgentsassignPhoneAgentremovePhoneAgentgetLiveSnapshotlistLiveAgentssetAgentRoutingpreviewAgentRoutingsetAgentPresencelistAgentPresenceslistQueuesgetQueuegetCallReportgetLiveKpisgetAgentPerformancelistMissedCallsrequestMissedCallCallbackgetAgentActivitygetQueueSettingssetQueueSettingsgetCallHandlingSettingssetCallHandlingSettingsgetQueuePerformancelistSkillscreateSkilldeleteSkillsetQueueSkillremoveQueueSkill
operator
Schemas
ManagerStatusPhoneAgentAssignPhoneAgentRequestProviderSetupProviderSetupSummaryProviderSetupRequestCustomerBatchSearchResultCustomerSearchResultCustomerIdentifierCustomerSummaryActiveCallActiveCallReportAgentStateAgentPresenceAgentPresenceRequestAgentPresenceChangeSkillQueueRefPersonRefEligibilityPathAgentQueueEligibilityLiveAgentLiveAgentCountersQueueHealthQueueLiveLiveSnapshotQueueRoutingStepQueueOverviewEligibleAgentWaitingCallQueueDetailAgentRoutingRequestAgentRoutingAgentRoutingPreviewCallReportQueuePerformanceQueuePerformanceReportSkillCatalogueEntrySkillCatalogueCreateSkillRequestSkillDeletionQueueSkillChangeErrorResponseKpiPeriodLiveKpisAgentPerformanceAgentPerformanceReportMissedCallCallerMissedCallCallbackMissedCallCallbackRequestMissedCallMissedCallListAgentActivityEventAgentPresenceTotalAgentActivityQueueSettingsUpdateQueueSettingsWrapUpTimesCallHandlingSettings
batchSearchCustomersโ
Resolves up to 50 identifiers to epilot customers (Contacts) in one request โ for example every number in an agent's call history.
GET /v1/customer:batchSearch
const { data } = await client.batchSearchCustomers({
id: ['...'],
customer_number: ['...'],
external_id: ['...'],
phone_number: ['...'],
email: ['...'],
x-trace-id: 'example',
})
Response
{
"results": [
{
"identifier": {
"type": "id",
"value": "+4917012345678"
},
"status": "found",
"customer": {
"id": "dba8e5f9-8b3f-4608-b887-cd0798fce624",
"name": "Max Mustermann",
"customer_number": "4711"
}
}
]
}
getActiveCallโ
Whether the signed-in user is on a phone call right now, and which conversation it is. The answer is about the caller only (the user of the bearer token).
GET /v1/calls/active
const { data } = await client.getActiveCall()
Response
{
"on_call": true,
"conversation_id": "01KW704DAM1PM5SDGKFDY9BNK0",
"started_at": "1970-01-01T00:00:00.000Z",
"source": "softphone",
"expires_at": "1970-01-01T00:00:00.000Z"
}
reportActiveCallโ
Reports the call the signed-in user is on. Sent by the epilot 360 phone when a call is
answered and again every 30 seconds while it lasts: a report is valid for 2 minutes
(expires_at), so a phone th
PUT /v1/calls/active
const { data } = await client.reportActiveCall(
null,
{
conversation_id: '01KW704DAM1PM5SDGKFDY9BNK0',
started_at: '2026-11-10T10:00:00.000Z'
},
)
Response
{
"on_call": true,
"conversation_id": "01KW704DAM1PM5SDGKFDY9BNK0",
"started_at": "1970-01-01T00:00:00.000Z",
"source": "softphone",
"expires_at": "1970-01-01T00:00:00.000Z"
}
clearActiveCallโ
Clears the signed-in user's reported call, when their part of it ended (hung up, or handed
over to another agent). With conversation_id, only a report of that conversation is
cleared, so a late "cal
DELETE /v1/calls/active
const { data } = await client.clearActiveCall({
conversation_id: 'example',
})
getManagerStatusโ
Whether the caller's organization is ready for phone agents: the telephony provider tenant
exists and is configured. The control center shows a "not set up" state when ready is false.
Requires `phon
GET /v1/manager/status
const { data } = await client.getManagerStatus()
Response
{
"provider": "babelforce",
"ready": true,
"reasons": ["provider_tenant_missing"]
}
listPhoneAgentsโ
Organization members who hold the phone (phone:use), each joined with the provider user behind
them. Requires phone:manage.
GET /v1/manager/agents
const { data } = await client.listPhoneAgents()
Response
{
"results": [
{
"user_id": "string",
"email": "string",
"display_name": "string",
"status": "active",
"provider_user_id": "string",
"provider_roles": ["string"],
"assigned_at": "1970-01-01T00:00:00.000Z",
"assigned_by": "string"
}
]
}
assignPhoneAgentโ
Gives an organization member the phone. In order: the member is verified with user-api, their pairwise subject for the provider is read from identity-api, the provider user is created (or found) bound
POST /v1/manager/agents
const { data } = await client.assignPhoneAgent(
null,
{
user_id: 'string'
},
)
Response
{
"user_id": "string",
"email": "string",
"display_name": "string",
"status": "active",
"provider_user_id": "string",
"provider_roles": ["string"],
"assigned_at": "1970-01-01T00:00:00.000Z",
"assigned_by": "string"
}
removePhoneAgentโ
Takes the phone away from a member: the phone_agent role is removed first, then the provider
user is deactivated (never deleted: call history keeps referring to it). Requires phone:manage.
DELETE /v1/manager/agents/{user_id}
const { data } = await client.removePhoneAgent({
user_id: 'example',
})
getLiveSnapshotโ
One snapshot of the organization's live phone state for the control center's Overview: agent presence counters and per-queue health (waiting calls, longest wait, eligible vs available agents). The pro
GET /v1/manager/live
const { data } = await client.getLiveSnapshot()
Response
{
"captured_at": "1970-01-01T00:00:00.000Z",
"agents": {
"total": 0,
"online": 0,
"available": 0,
"on_call": 0,
"wrap_up": 0,
"offline": 0
},
"queues": [
{
"id": "string",
"name": "string",
"waiting": 0,
"longest_wait_seconds": 0,
"expected_wait_seconds": 0,
"eligible": 0,
"available": 0,
"health": "healthy"
}
],
"calls_waiting": 0,
"longest_wait_seconds": 0,
"expected_wait_seconds": 0
}
listLiveAgentsโ
The organization's phone agents with their live phone status, their skills (as the phone system holds them) and the queues they can take calls from. Agents that are epilot phone agents carry the epilo
GET /v1/manager/agents/live
const { data } = await client.listLiveAgents()
Response
{
"captured_at": "1970-01-01T00:00:00.000Z",
"results": [
{
"provider_agent_id": "string",
"user_id": "string",
"name": "string",
"email": "string",
"enabled": true,
"state": "available",
"presence": {
"name": "string",
"label": "string",
"available": true
},
"display_status": "string",
"skills": ["string"],
"queues": [
{
"id": "string",
"name": "string",
"via": ["skill"],
"skills": ["string"],
"locked": true
}
],
"current_call": {
"started_at": "1970-01-01T00:00:00.000Z",
"queue_name": "string"
}
}
]
}
setAgentRoutingโ
Sets an agent's skills and direct queue membership (full sets, not deltas), in this order:
- Skills: the agent's skills in the phone system are replaced by
skills(lowercased, seeSkill), so t
PUT /v1/manager/agents/{provider_agent_id}/routing
const { data } = await client.setAgentRouting(
{
provider_agent_id: 'example',
},
{
skills: ['string'],
queue_ids: ['string'],
include_own_steps: false
},
)
Response
{
"provider_agent_id": "string",
"skills": ["string"],
"queues": [
{
"id": "string",
"name": "string",
"via": ["skill"],
"skills": ["string"],
"locked": true
}
]
}
previewAgentRoutingโ
The routing impact of setAgentRouting with the same body, without changing anything: the
queues the agent can take calls from now (as the phone system routes today) and after the
change, what is add
POST /v1/manager/agents/{provider_agent_id}/routing:preview
const { data } = await client.previewAgentRouting(
{
provider_agent_id: 'example',
},
{
skills: ['string'],
queue_ids: ['string'],
include_own_steps: false
},
)
Response
{
"provider_agent_id": "string",
"before": [
{
"id": "string",
"name": "string"
}
],
"after": [
{
"id": "string",
"name": "string"
}
],
"added": [
{
"id": "string",
"name": "string"
}
],
"removed": [
{
"id": "string",
"name": "string"
}
],
"coverage_lost": [
{
"id": "string",
"name": "string"
}
],
"locked": [
{
"id": "string",
"name": "string"
}
]
}
setAgentPresenceโ
Puts the agent on one of the phone system's presences (listAgentPresences), as the agent could
in the phone app. A presence that is not available stops queue calls to the agent until it
changes ag
PUT /v1/manager/agents/{provider_agent_id}/presence
const { data } = await client.setAgentPresence(
{
provider_agent_id: 'example',
},
{
presence: 'string'
},
)
Response
{
"provider_agent_id": "string",
"presence": {
"name": "string",
"label": "string",
"available": true
}
}
listAgentPresencesโ
The presences the organization's agents can be on (e.g. Available, Break, Meeting), as the phone
system defines them. available presences let agents take queue calls. Requires phone:manage.
GET /v1/manager/presences
const { data } = await client.listAgentPresences()
Response
{
"results": [
{
"name": "string",
"label": "string",
"available": true
}
]
}
listQueuesโ
The organization's queues with live demand (waiting calls, longest wait), staffing (eligible vs available agents), derived health and who can take their calls: the routing steps in the order the phone
GET /v1/manager/queues
const { data } = await client.listQueues()
Response
{
"captured_at": "1970-01-01T00:00:00.000Z",
"results": [
{
"id": "string",
"name": "string",
"waiting": 0,
"longest_wait_seconds": 0,
"expected_wait_seconds": 0,
"eligible": 0,
"available": 0,
"health": "healthy",
"numbers": ["string"],
"routing": [
{
"id": "string",
"order": 0,
"label": "string",
"enabled": true,
"skills": ["string"],
"people": [
{
"provider_agent_id": "string",
"user_id": "string",
"name": "string"
}
],
"team_members": ["string"],
"managed_by_epilot": true
}
]
}
]
}
getQueueโ
One queue for the control center's queue drawer: the overview fields plus the agents currently eligible for it (with live status and how they are eligible) and the calls waiting in it. Requires `phone
GET /v1/manager/queues/{queue_id}
const { data } = await client.getQueue({
queue_id: 'example',
})
Response
{
"id": "string",
"name": "string",
"waiting": 0,
"longest_wait_seconds": 0,
"expected_wait_seconds": 0,
"eligible": 0,
"available": 0,
"health": "healthy",
"numbers": ["string"],
"routing": [
{
"id": "string",
"order": 0,
"label": "string",
"enabled": true,
"skills": ["string"],
"people": [
{
"provider_agent_id": "string",
"user_id": "string",
"name": "string"
}
],
"team_members": ["string"],
"managed_by_epilot": true
}
],
"captured_at": "1970-01-01T00:00:00.000Z",
"eligible_agents": [
{
"provider_agent_id": "string",
"user_id": "string",
"name": "string",
"email": "string",
"state": "available",
"presence": {
"name": "string",
"label": "string",
"available": true
},
"via": ["skill"],
"skills": ["string"]
}
],
"waiting_calls": [
{
"id": "string",
"from_masked": "string",
"contact": {
"id": "string",
"name": "string"
},
"waited_seconds": 0,
"state": "string"
}
]
}
getCallReportโ
Inbound call outcomes for a period, from the provider's call reporting: how many inbound calls there were, how many an agent handled (bridged) and how many ended without an agent (abandoned or failed)
GET /v1/manager/reporting/calls
const { data } = await client.getCallReport({
from: 'example',
to: 'example',
})
Response
{
"from": "1970-01-01T00:00:00.000Z",
"to": "1970-01-01T00:00:00.000Z",
"inbound_total": 0,
"handled_by_agent": 0,
"abandoned_or_failed": 0,
"previous_period": {
"from": "1970-01-01T00:00:00.000Z",
"to": "1970-01-01T00:00:00.000Z",
"inbound_total": 0
}
}
getLiveKpisโ
Service KPIs of the organization's phone team for a period: call counts, abandon rate, waits and handling times, from the provider's metrics or, where it has none, its call reporting. A KPI the provid
GET /v1/manager/live/kpis
const { data } = await client.getLiveKpis({
period: 'example',
from: 'example',
to: 'example',
})
Response
{
"captured_at": "1970-01-01T00:00:00.000Z",
"period": "today",
"calls_total": 0,
"answered_total": 0,
"abandoned_total": 0,
"abandon_rate_percent": 0,
"average_wait_seconds": 0,
"longest_wait_seconds": 0,
"average_talk_seconds": 0,
"average_handle_seconds": 0,
"average_hold_seconds": 0
}
getAgentPerformanceโ
Per-agent performance for a period from the provider's call reporting: calls handled and talk, hold, wrap-up and handle times, one row per agent who handled at least one call. Agents that are epilot p
GET /v1/manager/reporting/agents
const { data } = await client.getAgentPerformance({
from: 'example',
to: 'example',
})
Response
{
"from": "1970-01-01T00:00:00.000Z",
"to": "1970-01-01T00:00:00.000Z",
"results": [
{
"provider_agent_id": "string",
"user_id": "string",
"name": "string",
"calls_handled": 0,
"outbound_calls": 0,
"talk_seconds_total": 0,
"talk_seconds_average": 0,
"hold_seconds_total": 0,
"wrap_up_seconds_average": 0,
"handle_seconds_average": 0
}
]
}
listMissedCallsโ
Callers who did not reach an agent in a period, newest first, one row per caller: an inbound call (grouped by the provider's session, so transfer legs count once) that ended without being bridged to a
GET /v1/manager/missed-calls
const { data } = await client.listMissedCalls({
from: 'example',
to: 'example',
})
Response
{
"from": "1970-01-01T00:00:00.000Z",
"to": "1970-01-01T00:00:00.000Z",
"results": [
{
"call_id": "string",
"last_missed_at": "1970-01-01T00:00:00.000Z",
"first_missed_at": "1970-01-01T00:00:00.000Z",
"attempts": 1,
"queue": {
"id": "string",
"name": "string"
},
"longest_wait_seconds": 0,
"caller": {
"anonymous": true,
"number_masked": "string",
"contact": {
"id": "string",
"name": "string"
}
},
"resolved": true,
"can_call_back": true,
"callback": {
"state": "queued",
"requested_at": "1970-01-01T00:00:00.000Z",
"requested_by": "string",
"queue": {
"id": "string",
"name": "string"
},
"callback_call_id": "string"
}
}
]
}
requestMissedCallCallbackโ
Asks the phone system to call the caller of a missed call back: the provider queues an outbound
callback on a queue (the missed call's queue unless queue_id names another), so the next
eligible agen
POST /v1/manager/missed-calls/{call_id}/callback
const { data } = await client.requestMissedCallCallback(
{
call_id: 'example',
},
{
queue_id: 'string'
},
)
getAgentActivityโ
An agent's activity in a period from the provider's agent logs: presence changes and calls in time order, the time spent on each presence and the number of calls handled. The window is at most 31 days
GET /v1/manager/agents/{provider_agent_id}/activity
const { data } = await client.getAgentActivity({
provider_agent_id: 'example',
from: 'example',
to: 'example',
})
Response
{
"provider_agent_id": "string",
"from": "1970-01-01T00:00:00.000Z",
"to": "1970-01-01T00:00:00.000Z",
"events": [
{
"at": "1970-01-01T00:00:00.000Z",
"kind": "presence",
"presence": {
"name": "string",
"label": "string",
"available": true
},
"call": {
"call_id": "string",
"direction": "inbound",
"queue_name": "string",
"duration_seconds": 0
},
"description": "string"
}
],
"presence_totals": [
{
"presence": {
"name": "string",
"label": "string",
"available": true
},
"seconds": 0
}
],
"calls_handled": 0
}
getQueueSettingsโ
A queue's call handling settings as the phone system holds them: how many callers may wait, how long an agent's phone rings, the wrap-up time after a call and how many agents are tried per call. Requi
GET /v1/manager/queues/{queue_id}/settings
const { data } = await client.getQueueSettings({
queue_id: 'example',
})
Response
{
"queue_id": "string",
"name": "string",
"max_size": 0,
"ring_timeout_seconds": 5,
"wrap_up_seconds": 0,
"max_dial_count": 1
}
setQueueSettingsโ
Replaces a queue's call handling settings (all fields, not a delta); the phone system applies
them to the next call. The queue's name and routing are not changed.
Requires phone:manage.
PUT /v1/manager/queues/{queue_id}/settings
const { data } = await client.setQueueSettings(
{
queue_id: 'example',
},
{
max_size: 0,
ring_timeout_seconds: 5,
wrap_up_seconds: 0,
max_dial_count: 1
},
)
Response
{
"queue_id": "string",
"name": "string",
"max_size": 0,
"ring_timeout_seconds": 5,
"wrap_up_seconds": 0,
"max_dial_count": 1
}
getCallHandlingSettingsโ
The organization's call handling settings for all agents: wrap-up rules (including whether agents may call out during wrap-up), wrap-up times after unsuccessful calls, and recording defaults. Requires
GET /v1/manager/settings/call-handling
const { data } = await client.getCallHandlingSettings()
Response
{
"wrap_up": {
"inbound_cancel_allowed": true,
"inbound_extend_allowed": true,
"inbound_max_extension_seconds": 0,
"outbound_enabled": true,
"outbound_cancel_allowed": true,
"outbound_extend_allowed": true,
"outbound_max_extension_seconds": 0,
"outbound_calls_allowed": true
},
"after_unsuccessful_inbound": {
"busy_seconds": 0,
"unreachable_seconds": 0,
"declined_seconds": 0
},
"after_unsuccessful_outbound": {
"busy_seconds": 0,
"unreachable_seconds": 0,
"declined_seconds": 0
},
"recording": {
"always_record_outbound": true,
"agents_may_delete": true,
"hide_recording_controls": true
}
}
setCallHandlingSettingsโ
Replaces the organization's call handling settings (the full object, not a delta).
Requires phone:manage.
PUT /v1/manager/settings/call-handling
const { data } = await client.setCallHandlingSettings(
null,
{
wrap_up: {
inbound_cancel_allowed: true,
inbound_extend_allowed: true,
inbound_max_extension_seconds: 0,
outbound_enabled: true,
outbound_cancel_allowed: true,
outbound_extend_allowed: true,
outbound_max_extension_seconds: 0,
outbound_calls_allowed: true
},
after_unsuccessful_inbound: {
busy_seconds: 0,
unreachable_seconds: 0,
declined_seconds: 0
},
after_unsuccessful_outbound: {
busy_seconds: 0,
unreachable_seconds: 0,
declined_seconds: 0
},
recording: {
always_record_outbound: true,
agents_may_delete: true,
hide_recording_controls: true
}
},
)
Response
{
"wrap_up": {
"inbound_cancel_allowed": true,
"inbound_extend_allowed": true,
"inbound_max_extension_seconds": 0,
"outbound_enabled": true,
"outbound_cancel_allowed": true,
"outbound_extend_allowed": true,
"outbound_max_extension_seconds": 0,
"outbound_calls_allowed": true
},
"after_unsuccessful_inbound": {
"busy_seconds": 0,
"unreachable_seconds": 0,
"declined_seconds": 0
},
"after_unsuccessful_outbound": {
"busy_seconds": 0,
"unreachable_seconds": 0,
"declined_seconds": 0
},
"recording": {
"always_record_outbound": true,
"agents_may_delete": true,
"hide_recording_controls": true
}
}
getQueuePerformanceโ
Inbound call outcomes per queue for a period, derived from the provider's call reporting (the phone system has no per-queue report): every inbound call that started in [from, to) is counted for the qu
GET /v1/manager/reporting/queues
const { data } = await client.getQueuePerformance({
from: 'example',
to: 'example',
})
Response
{
"from": "1970-01-01T00:00:00.000Z",
"to": "1970-01-01T00:00:00.000Z",
"results": [
{
"queue": {
"id": "string",
"name": "string"
},
"inbound_total": 0,
"handled_by_agent": 0,
"abandoned_or_failed": 0,
"abandon_rate_percent": 0,
"average_wait_seconds": 0
}
]
}
listSkillsโ
The organization's skill catalogue: the skills epilot keeps for it (created in the control
center, source: epilot) together with every skill the phone system already uses on an agent or
in a queue's
GET /v1/manager/skills
const { data } = await client.listSkills()
Response
{
"results": [
{
"tag": "string",
"source": "epilot",
"created_at": "1970-01-01T00:00:00.000Z",
"created_by": "string"
}
]
}
createSkillโ
Adds a skill to the organization's catalogue (epilot only: nothing is written to the phone system until an agent gets the skill or a queue accepts it). The skill is trimmed, must then be 1 to 100 char
POST /v1/manager/skills
const { data } = await client.createSkill(
null,
{
tag: 'string'
},
)
Response
{
"tag": "string",
"source": "epilot",
"created_at": "1970-01-01T00:00:00.000Z",
"created_by": "string"
}
deleteSkillโ
Deletes a skill everywhere (in any letter case, see Skill): it is taken from every agent that has it and from every routing step
of every queue that accepts it in the phone system, then removed from
DELETE /v1/manager/skills/{tag}
const { data } = await client.deleteSkill({
tag: 'example',
})
Response
{
"tag": "string",
"agents_updated": 0,
"queues_updated": 0
}
setQueueSkillโ
The queue accepts the skill: every agent with it can take the queue's calls. epilot adds the skill to the queue's FIRST enabled routing step of the organization's own in the phone system (lowest order
PUT /v1/manager/queues/{queue_id}/skills/{tag}
const { data } = await client.setQueueSkill({
queue_id: 'example',
tag: 'example',
})
Response
{
"queue": {
"id": "string",
"name": "string"
},
"tag": "string",
"accepted": true,
"step": {
"id": "string",
"label": "string"
}
}
removeQueueSkillโ
The queue no longer accepts the skill: it is removed from every routing step of the queue that
lists it (enabled or not). Idempotent. Requires phone:manage.
DELETE /v1/manager/queues/{queue_id}/skills/{tag}
const { data } = await client.removeQueueSkill({
queue_id: 'example',
tag: 'example',
})
Response
{
"queue": {
"id": "string",
"name": "string"
},
"tag": "string",
"accepted": true,
"step": {
"id": "string",
"label": "string"
}
}
listProviderSetupsโ
Every organization that has a telephony provider tenant, for the admin portal's overview: the provider's sub-accounts (one per organization, keyed by the organization id) joined with this service's se
GET /v1/operator/provider-setups
const { data } = await client.listProviderSetups()
Response
{
"results": [
{
"org_id": "string",
"provider": "babelforce",
"ready": true,
"setup_recorded": true,
"tenant": {
"id": "string",
"name": "string",
"org_key": "string"
},
"sso_identity_client_id": "string",
"last_setup_by": "string",
"updated_at": "1970-01-01T00:00:00.000Z"
}
]
}
getProviderSetupโ
What has been set up at the telephony provider for this organization.
GET /v1/operator/organizations/{org_id}/provider
const { data } = await client.getProviderSetup({
org_id: 'example',
})
Response
{
"provider": "babelforce",
"org_id": "string",
"ready": true,
"tenant": {
"id": "string",
"name": "string",
"org_key": "string",
"created_at": "1970-01-01T00:00:00.000Z"
},
"scim": {
"configured": true,
"roles_enabled": true
},
"sso": {
"configured": true,
"identity_client_id": "string",
"configured_at": "1970-01-01T00:00:00.000Z"
},
"last_setup_by": "string"
}
setupProviderโ
Prepares the telephony provider for an organization, idempotently and in order: the provider tenant (Babelforce sub-account keyed by the organization id), its SCIM configuration with role management o
POST /v1/operator/organizations/{org_id}/provider:setup
const { data } = await client.setupProvider(
{
org_id: 'example',
},
{
account_name: 'string',
identity_client_id: 'string',
identity_client_secret: 'stringstring'
},
)
Response
{
"provider": "babelforce",
"org_id": "string",
"ready": true,
"tenant": {
"id": "string",
"name": "string",
"org_key": "string",
"created_at": "1970-01-01T00:00:00.000Z"
},
"scim": {
"configured": true,
"roles_enabled": true
},
"sso": {
"configured": true,
"identity_client_id": "string",
"configured_at": "1970-01-01T00:00:00.000Z"
},
"last_setup_by": "string"
}
Schemasโ
ManagerStatusโ
type ManagerStatus = {
provider: "babelforce"
ready: boolean
reasons: "provider_tenant_missing" | "sso_not_configured" | "scim_not_configured" | "identity_enablement_missing"[]
}
PhoneAgentโ
type PhoneAgent = {
user_id: string
email: string
display_name?: string
status: "active" | "pending" | "disabled" | "missing_provider" | "missing_role"
provider_user_id?: string
provider_roles?: string[]
assigned_at?: string // date-time
assigned_by?: string
}
AssignPhoneAgentRequestโ
type AssignPhoneAgentRequest = {
user_id: string
}
ProviderSetupโ
type ProviderSetup = {
provider: "babelforce"
org_id: string
ready: boolean
tenant: {
id: string
name: string
org_key: string
created_at?: string // date-time
}
scim: {
configured: boolean
roles_enabled: boolean
}
sso: {
configured: boolean
identity_client_id?: string
configured_at?: string // date-time
}
last_setup_by?: string
}
ProviderSetupSummaryโ
One organization's provider setup, as listed in the overview (no live SCIM or SSO reads).
type ProviderSetupSummary = {
org_id: string
provider: "babelforce"
ready: boolean
setup_recorded: boolean
tenant: {
id: string
name: string
org_key: string
}
sso_identity_client_id?: string
last_setup_by?: string
updated_at?: string // date-time
}
ProviderSetupRequestโ
type ProviderSetupRequest = {
account_name?: string
identity_client_id: string
identity_client_secret: string
}
CustomerBatchSearchResultโ
type CustomerBatchSearchResult = {
results: Array<{
identifier: {
type: { ... }
value: { ... }
}
status: "found" | "not_found" | "ambiguous" | "invalid" | "error"
customer?: {
id: { ... }
name: { ... }
customer_number?: { ... }
}
}>
}
CustomerSearchResultโ
type CustomerSearchResult = {
identifier: {
type: "id" | "customer_number" | "external_id" | "phone_number" | "email"
value: string
}
status: "found" | "not_found" | "ambiguous" | "invalid" | "error"
customer?: {
id: string
name: string
customer_number?: string
}
}
CustomerIdentifierโ
type CustomerIdentifier = {
type: "id" | "customer_number" | "external_id" | "phone_number" | "email"
value: string
}
CustomerSummaryโ
Present when status is found
type CustomerSummary = {
id: string
name: string
customer_number?: string
}
ActiveCallโ
The phone call a user is on right now.
type ActiveCall = {
on_call: boolean
conversation_id?: string
started_at?: string // date-time
source?: "softphone" | "provider"
expires_at?: string // date-time
}
ActiveCallReportโ
type ActiveCallReport = {
conversation_id: string
started_at?: string
}
AgentStateโ
The agent's live line state as the provider reports it, plus busy for anyone who cannot take a
queue call for a reason other than a call: on a presence that takes no calls (e.g. Busy, Break),
without a presence, or disabled at the provider; busy also covers the provider's busy line
state. `unkno
type AgentState = "available" | "ringing" | "in_call" | "wrap_up" | "busy" | "declined" | "unreachable" | "selected" | "offline" | "unknown"
AgentPresenceโ
The provider presence the agent has selected (e.g. Available, Break, Meeting)
type AgentPresence = {
name: string
label: string
available: boolean
}
AgentPresenceRequestโ
type AgentPresenceRequest = {
presence: string
}
AgentPresenceChangeโ
type AgentPresenceChange = {
provider_agent_id: string
presence: {
name: string
label: string
available: boolean
}
}
Skillโ
A skill as the phone system holds it (Babelforce: an agent tag). epilot's convention for skills is
<skill category>:<label> (e.g. language:german), which the control center shows as
"Category ยท Label"; a skill without a colon has no category.
Skills are case-insensitive and stored lowercased, in
type Skill = string
QueueRefโ
type QueueRef = {
id: string
name: string
}
PersonRefโ
An agent as a routing step names them
type PersonRef = {
provider_agent_id: string
user_id?: string
name: string
}
EligibilityPathโ
How an agent can take a queue's calls:
skill: the queue routes to people with a skill the agent has (changes with the agent's skills);direct: a step of the queue names the agent, the epilot-managed one or one set up in the phone system; the control center can take them off the queue;- `r
type EligibilityPath = "skill" | "direct" | "routing"
AgentQueueEligibilityโ
A queue an agent can take calls from, and why
type AgentQueueEligibility = {
id: string
name: string
via: "skill" | "direct" | "routing"[]
skills: string[]
locked: boolean
}
LiveAgentโ
type LiveAgent = {
provider_agent_id: string
user_id?: string
name: string
email?: string
enabled: boolean
state: "available" | "ringing" | "in_call" | "wrap_up" | "busy" | "declined" | "unreachable" | "selected" | "offline" | "unknown"
presence?: {
name: string
label: string
available: boolean
}
display_status?: string
skills: string[]
queues: Array<{
id: string
name: string
via: "skill" | "direct" | "routing"[]
skills: string[]
locked: boolean
}>
current_call?: {
started_at: string // date-time
queue_name?: string
}
}
LiveAgentCountersโ
Presence counters over the organization's agents
type LiveAgentCounters = {
total: number
online: number
available: number
on_call: number
wrap_up: number
offline: number
}
QueueHealthโ
at_risk: a waiting caller has no agent to take them: every caller not yet with an agent needs
their own eligible agent who is available or being rung, one agent counting once across the
queues of the same answer (so three callers and one free agent, or two queues sharing one free
agent, are at ris
type QueueHealth = "healthy" | "at_risk" | "quiet"
QueueLiveโ
Live demand and staffing of one queue
type QueueLive = {
id: string
name: string
waiting: number
longest_wait_seconds?: number
expected_wait_seconds?: number
eligible: number
available: number
health: "healthy" | "at_risk" | "quiet"
}
LiveSnapshotโ
type LiveSnapshot = {
captured_at: string // date-time
agents: {
total: number
online: number
available: number
on_call: number
wrap_up: number
offline: number
}
queues: Array<{
id: string
name: string
waiting: number
longest_wait_seconds?: number
expected_wait_seconds?: number
eligible: number
available: number
health: "healthy" | "at_risk" | "quiet"
}>
calls_waiting: number
longest_wait_seconds?: number
expected_wait_seconds?: number
}
QueueRoutingStepโ
One step of who can take a queue's calls, in the order the phone system tries them. A step
offers calls to the people it names and to everyone with any of its skills. Teams set up in the
phone system appear as the people they contain (team_members). The epilot-managed step holds
the people added f
type QueueRoutingStep = {
id: string
order: number
label: string
enabled: boolean
skills: string[]
people: Array<{
provider_agent_id: string
user_id?: string
name: string
}>
team_members: string[]
managed_by_epilot: boolean
}
QueueOverviewโ
type QueueOverview = {
id: string
name: string
waiting: number
longest_wait_seconds?: number
expected_wait_seconds?: number
eligible: number
available: number
health: "healthy" | "at_risk" | "quiet"
numbers?: string[]
routing: Array<{
id: string
order: number
label: string
enabled: boolean
skills: string[]
people: Array<{
provider_agent_id: { ... }
user_id?: { ... }
name: { ... }
}>
team_members: string[]
managed_by_epilot: boolean
}>
}
EligibleAgentโ
An agent who can take the queue's calls, with live status
type EligibleAgent = {
provider_agent_id: string
user_id?: string
name: string
email?: string
state: "available" | "ringing" | "in_call" | "wrap_up" | "busy" | "declined" | "unreachable" | "selected" | "offline" | "unknown"
presence?: {
name: string
label: string
available: boolean
}
via: "skill" | "direct" | "routing"[]
skills: string[]
}
WaitingCallโ
type WaitingCall = {
id: string
from_masked?: string
contact?: {
id: string
name: string
}
waited_seconds: number
state: string
}
QueueDetailโ
type QueueDetail = {
captured_at: string // date-time
eligible_agents: Array<{
provider_agent_id: string
user_id?: string
name: string
email?: string
state: "available" | "ringing" | "in_call" | "wrap_up" | "busy" | "declined" | "unreachable" | "selected" | "offline" | "unknown"
presence?: {
name: { ... }
label: { ... }
available: { ... }
}
via: "skill" | "direct" | "routing"[]
skills: string[]
}>
waiting_calls: Array<{
id: string
from_masked?: string
contact?: {
id: { ... }
name: { ... }
}
waited_seconds: number
state: string
}>
}
AgentRoutingRequestโ
type AgentRoutingRequest = {
skills: string[]
queue_ids: string[]
include_own_steps?: boolean
}
AgentRoutingโ
type AgentRouting = {
provider_agent_id: string
skills: string[]
queues: Array<{
id: string
name: string
via: "skill" | "direct" | "routing"[]
skills: string[]
locked: boolean
}>
}
AgentRoutingPreviewโ
type AgentRoutingPreview = {
provider_agent_id: string
before: Array<{
id: string
name: string
}>
after: Array<{
id: string
name: string
}>
added: Array<{
id: string
name: string
}>
removed: Array<{
id: string
name: string
}>
coverage_lost: Array<{
id: string
name: string
}>
locked: Array<{
id: string
name: string
}>
}
CallReportโ
type CallReport = {
from: string // date-time
to: string // date-time
inbound_total: number
handled_by_agent: number
abandoned_or_failed: number
previous_period: {
from: string // date-time
to: string // date-time
inbound_total: number
}
}
QueuePerformanceโ
type QueuePerformance = {
queue: {
id: string
name: string
}
inbound_total: number
handled_by_agent: number
abandoned_or_failed: number
abandon_rate_percent: number
average_wait_seconds?: number
}
QueuePerformanceReportโ
type QueuePerformanceReport = {
from: string // date-time
to: string // date-time
results: Array<{
queue: {
id: { ... }
name: { ... }
}
inbound_total: number
handled_by_agent: number
abandoned_or_failed: number
abandon_rate_percent: number
average_wait_seconds?: number
}>
}
SkillCatalogueEntryโ
type SkillCatalogueEntry = {
tag: string
source: "epilot" | "provider"
created_at?: string // date-time
created_by?: string
}
SkillCatalogueโ
type SkillCatalogue = {
results: Array<{
tag: string
source: "epilot" | "provider"
created_at?: string // date-time
created_by?: string
}>
}
CreateSkillRequestโ
type CreateSkillRequest = {
tag: string
}
SkillDeletionโ
type SkillDeletion = {
tag: string
agents_updated: number
queues_updated: number
}
QueueSkillChangeโ
type QueueSkillChange = {
queue: {
id: string
name: string
}
tag: string
accepted: boolean
step?: {
id: string
label: string
}
}
ErrorResponseโ
type ErrorResponse = {
status: number
error: string
code?: string
}
KpiPeriodโ
The KPI window, in the organization's phone system time zone: today, yesterday, this week
(since Monday), last week (Monday to Monday), last 7 / 30 days (seven / thirty calendar days
including today), this month, last month; custom is the window from/to of the request.
type KpiPeriod = "today" | "yesterday" | "this_week" | "last_week" | "last_7_days" | "last_30_days" | "this_month" | "last_month" | "custom"
LiveKpisโ
Every KPI is absent when the phone system cannot tell it.
type LiveKpis = {
captured_at: string // date-time
period: "today" | "yesterday" | "this_week" | "last_week" | "last_7_days" | "last_30_days" | "this_month" | "last_month" | "custom"
calls_total?: number
answered_total?: number
abandoned_total?: number
abandon_rate_percent?: number
average_wait_seconds?: number
longest_wait_seconds?: number
average_talk_seconds?: number
average_handle_seconds?: number
average_hold_seconds?: number
}
AgentPerformanceโ
type AgentPerformance = {
provider_agent_id?: string
user_id?: string
name: string
calls_handled: number
outbound_calls?: number
talk_seconds_total: number
talk_seconds_average: number
hold_seconds_total?: number
wrap_up_seconds_average?: number
handle_seconds_average: number
}
AgentPerformanceReportโ
type AgentPerformanceReport = {
from: string // date-time
to: string // date-time
results: Array<{
provider_agent_id?: string
user_id?: string
name: string
calls_handled: number
outbound_calls?: number
talk_seconds_total: number
talk_seconds_average: number
hold_seconds_total?: number
wrap_up_seconds_average?: number
handle_seconds_average: number
}>
}
MissedCallCallerโ
type MissedCallCaller = {
anonymous: boolean
number_masked?: string
contact?: {
id: string
name: string
}
}
MissedCallCallbackโ
type MissedCallCallback = {
state: "queued" | "ringing" | "in_progress" | "completed" | "failed" | "canceled" | "unknown"
requested_at: string // date-time
requested_by?: string
queue?: {
id: string
name: string
}
callback_call_id?: string
}
MissedCallCallbackRequestโ
type MissedCallCallbackRequest = {
queue_id?: string
}
MissedCallโ
type MissedCall = {
call_id: string
last_missed_at: string // date-time
first_missed_at?: string // date-time
attempts: number
queue?: {
id: string
name: string
}
longest_wait_seconds?: number
caller: {
anonymous: boolean
number_masked?: string
contact?: {
id: { ... }
name: { ... }
}
}
resolved: boolean
can_call_back: boolean
callback?: {
state: "queued" | "ringing" | "in_progress" | "completed" | "failed" | "canceled" | "unknown"
requested_at: string // date-time
requested_by?: string
queue?: {
id: { ... }
name: { ... }
}
callback_call_id?: string
}
}
MissedCallListโ
type MissedCallList = {
from: string // date-time
to: string // date-time
results: Array<{
call_id: string
last_missed_at: string // date-time
first_missed_at?: string // date-time
attempts: number
queue?: {
id: { ... }
name: { ... }
}
longest_wait_seconds?: number
caller: {
anonymous: { ... }
number_masked?: { ... }
contact?: { ... }
}
resolved: boolean
can_call_back: boolean
callback?: {
state: { ... }
requested_at: { ... }
requested_by?: { ... }
queue?: { ... }
callback_call_id?: { ... }
}
}>
}
AgentActivityEventโ
type AgentActivityEvent = {
at: string // date-time
kind: "presence" | "call" | "state" | "other"
presence?: {
name: string
label: string
available: boolean
}
call?: {
call_id?: string
direction?: "inbound" | "outbound"
queue_name?: string
duration_seconds?: number
}
description?: string
}
AgentPresenceTotalโ
type AgentPresenceTotal = {
presence: {
name: string
label: string
available: boolean
}
seconds: number
}
AgentActivityโ
type AgentActivity = {
provider_agent_id: string
from: string // date-time
to: string // date-time
events: Array<{
at: string // date-time
kind: "presence" | "call" | "state" | "other"
presence?: {
name: { ... }
label: { ... }
available: { ... }
}
call?: {
call_id?: { ... }
direction?: { ... }
queue_name?: { ... }
duration_seconds?: { ... }
}
description?: string
}>
presence_totals: Array<{
presence: {
name: { ... }
label: { ... }
available: { ... }
}
seconds: number
}>
calls_handled: number
}
QueueSettingsUpdateโ
type QueueSettingsUpdate = {
max_size: number
ring_timeout_seconds: number
wrap_up_seconds: number
max_dial_count: number
}
QueueSettingsโ
type QueueSettings = {
queue_id: string
name: string
max_size: number
ring_timeout_seconds: number
wrap_up_seconds: number
max_dial_count: number
}
WrapUpTimesโ
type WrapUpTimes = {
busy_seconds: number
unreachable_seconds: number
declined_seconds: number
}
CallHandlingSettingsโ
type CallHandlingSettings = {
wrap_up: {
inbound_cancel_allowed: boolean
inbound_extend_allowed: boolean
inbound_max_extension_seconds: number
outbound_enabled: boolean
outbound_cancel_allowed: boolean
outbound_extend_allowed: boolean
outbound_max_extension_seconds: number
outbound_calls_allowed: boolean
}
after_unsuccessful_inbound: {
busy_seconds: number
unreachable_seconds: number
declined_seconds: number
}
after_unsuccessful_outbound: {
busy_seconds: number
unreachable_seconds: number
declined_seconds: number
}
recording: {
always_record_outbound: boolean
agents_may_delete: boolean
hide_recording_controls: boolean
}
}