Analytics

How the calling went, at whatever grain you need.

Four grains, and which one you want depends on the question. The overview aggregates every campaign the key can reach. Campaign analytics covers one campaign across all of its runs. Run analytics covers a single attempt, which is the only grain where a before-and-after comparison means anything. Realtime covers what is happening right now.

Inbound campaigns are reported separately because the questions are different: an outbound campaign is judged on whether it reached people, an inbound one on whether it answered them.

Analysis-derived figures (sentiment, whether a human was reached, intent, resolution) only cover calls that have finished being analysed, so they lag the call counts slightly on a campaign that is still running. Rates are whole percentages from 0 to 100. Sentiment scores run from -1 (negative) to 1 (positive). Figures the platform does not measure yet, such as cost and objective success, are reported as 0.

Get an analytics overview#

Totals across every campaign the key can reach, with a daily series and the five campaigns with the most calls. Defaults to the last 30 days.

GET/api/v1/analytics/overview

Query parameters

dateFromstring
YYYY-MM-DD. Defaults to 30 days ago.
dateTostring
YYYY-MM-DD. Defaults to today.

Responses

The overview. `recentActivity` is newest first.

curl -X GET "https://voice.evryhealth.com/api/v1/analytics/overview" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"dateRange": {
"from": "2024-01-01",
"to": "2024-01-31"
},
"summary": {
"totalCampaigns": 12,
"activeCampaigns": 3,
"totalCalls": 4820,
"completedCalls": 4102,
"totalCost": 0
},
"aggregateMetrics": {
"avgHumanContactRate": 64,
"avgObjectiveSuccessRate": 0,
"avgSentiment": 0.41,
"avgComplianceScore": 0
},
"topCampaigns": [
{
"id": "357b188c-c618-4f95-84b1-cbe26b8ce3e0",
"name": "Q1 Provider Outreach",
"totalCalls": 1200,
"successRate": 86
}
],
"recentActivity": [
{
"date": "2024-01-31",
"calls": 210,
"completedCalls": 188
}
],
"lastUpdated": "2024-01-31T18:00:00.000Z"
}

Get campaign analytics#

One campaign, across every run it has had, or one run of it with `runId`. `run` is the latest run when no `runId` is given, and null when the campaign has never run.

GET/api/v1/campaigns/{id}/analytics

Path parameters

idstringrequired
Campaign id.

Query parameters

runIdstring
Limit the figures to one run of this campaign. A run that is not this campaign's is a 404.

Responses

The campaign's analytics.

curl -X GET "https://voice.evryhealth.com/api/v1/campaigns/{id}/analytics" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"campaign": {
"id": "357b188c-c618-4f95-84b1-cbe26b8ce3e0",
"name": "Q1 Provider Outreach",
"status": "active",
"direction": "outbound"
},
"run": {
"id": "0f6d2a8e-1d0c-4b7a-9d55-2f1b6a3c9e10",
"runNumber": 3,
"status": "in_progress",
"startedAt": "2024-01-20T09:00:00.000Z",
"contactsAttempted": 500,
"contactsReached": 351
},
"metrics": {
"callStats": {
"totalCalls": 1200,
"completedCalls": 1032,
"failedCalls": 96,
"ongoingCalls": 2,
"queuedCalls": 70,
"cancelledCalls": 12,
"analyzedCalls": 1010,
"analysisProgress": 84
},
"successMetrics": {
"humanContactRate": 71,
"humanContactCount": 717,
"objectiveSuccessRate": 0,
"ivrEscapeRate": 0,
"ivrEscapeCount": 0,
"completionRate": 86
},
"qualityMetrics": {
"avgSentimentScore": 0.41,
"sentimentDistribution": {
"positive": 61,
"neutral": 32,
"negative": 7
},
"avgClarityScore": 0,
"avgEffectivenessScore": 0,
"avgRapportScore": 0,
"avgConfidence": 0
},
"complianceMetrics": {
"doNotCallCount": 4,
"doNotCallRate": 0,
"legalThreatCount": 0,
"legalThreatRate": 0,
"complianceScore": 96,
"complianceIssues": []
},
"costMetrics": {
"totalCost": 0,
"costPerCompletedCall": 0,
"costPerHumanContact": 0,
"costPerObjectiveAchieved": 0,
"breakdown": {
"llmCost": 0,
"voiceCost": 0,
"telephonyCost": 0
},
"totalTokens": {
"input": 0,
"output": 0
}
},
"performanceMetrics": {
"avgCallDuration": 212,
"avgIvrNavigationTime": 0,
"avgTimeToHuman": 0,
"callDurationDistribution": {
"under30s": 0,
"under1m": 0,
"under3m": 0,
"under5m": 0,
"over5m": 0
}
},
"informationQuality": {
"dataAccuracyRate": 0,
"totalInformationUpdates": 0,
"updatesByField": {},
"callsWithUpdates": 0,
"callsWithUpdatesRate": 0
}
},
"meta": {
"calculatedAt": "2024-01-20T14:12:00.000Z",
"isStale": false,
"analysisProgress": 84
}
}

Get an analytics summary#

The headline figures for a campaign, without the breakdowns.

GET/api/v1/campaigns/{id}/analytics/summary

Path parameters

idstringrequired
Campaign id.

Query parameters

runIdstring
Limit the figures to one run of this campaign. A run that is not this campaign's is a 404.

Responses

The summary. `avgCallDuration` is in seconds.

curl -X GET "https://voice.evryhealth.com/api/v1/campaigns/{id}/analytics/summary" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"campaign": {
"id": "357b188c-c618-4f95-84b1-cbe26b8ce3e0",
"name": "Q1 Provider Outreach",
"status": "active"
},
"kpis": {
"totalCalls": 1200,
"completedCalls": 1032,
"humanContactRate": 71,
"objectiveSuccessRate": 0,
"avgSentiment": 0.41,
"avgCallDuration": 212,
"complianceScore": 96,
"totalCost": 0
},
"lastUpdated": "2024-01-20T14:12:00.000Z"
}

Get realtime analytics#

What is happening now. An outbound campaign reports `outboundStatus` (queued calls, completed today, contacts not yet called); an inbound one reports `inboundStatus` instead. Days are UTC. Poll this while a campaign is dialling, or subscribe to the event stream instead.

GET/api/v1/campaigns/{id}/analytics/realtime

Path parameters

idstringrequired
Campaign id.

Responses

The live picture. `avgDurationToday` is in seconds.

curl -X GET "https://voice.evryhealth.com/api/v1/campaigns/{id}/analytics/realtime" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"realtime": {
"activeCalls": 5,
"callsInLastHour": 48,
"callsToday": 353,
"avgDurationToday": 205
},
"outboundStatus": {
"queuedCalls": 142,
"completedToday": 301,
"contactsRemaining": 410
},
"timestamp": "2024-01-20T14:12:00.000Z"
}

Get inbound analytics#

For campaigns that answer rather than dial: volume, answer rate, handle time, when people call, why they call and whether it was resolved. Defaults to the last 30 days. Wait time, abandonment and service level are not measured yet and are reported as 0.

GET/api/v1/campaigns/{id}/analytics/inbound

Path parameters

idstringrequired
Campaign id.

Query parameters

dateFromstring
YYYY-MM-DD.
dateTostring
YYYY-MM-DD.

Responses

The inbound analytics. Durations are in seconds.

curl -X GET "https://voice.evryhealth.com/api/v1/campaigns/{id}/analytics/inbound" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"campaign": {
"id": "357b188c-c618-4f95-84b1-cbe26b8ce3e0",
"name": "Member services line",
"phoneNumber": "+14155550100",
"status": "active",
"deployedAt": "2024-01-02T09:00:00.000Z"
},
"dateRange": {
"from": "2024-01-01",
"to": "2024-01-31"
},
"serviceMetrics": {
"totalCalls": 480,
"answeredCalls": 461,
"missedCalls": 19,
"answerRate": 96,
"avgWaitTime": 0,
"avgHandleTime": 184,
"abandonmentRate": 0,
"serviceLevelMet": 0
},
"volumePatterns": {
"totalCalls": 480,
"avgCallsPerHour": 20,
"avgCallsPerDay": 15,
"peakHour": 9,
"peakDay": "Monday",
"hourlyDistribution": [
{
"hour": 9,
"count": 41,
"avgDuration": 190
}
],
"dailyDistribution": [
{
"day": "Monday",
"count": 96,
"avgDuration": 181
}
],
"callVolumeTimeline": [
{
"date": "2024-01-02",
"count": 17,
"avgDuration": 176
}
]
},
"intentAnalysis": {
"totalCalls": 450,
"analyzedCalls": 450,
"intentDistribution": {
"support": {
"count": 270,
"percentage": 60,
"avgConfidence": 0
}
},
"urgencyDistribution": {
"low": {
"count": 180,
"percentage": 40
},
"medium": {
"count": 200,
"percentage": 44
},
"high": {
"count": 65,
"percentage": 14
},
"critical": {
"count": 5,
"percentage": 1
}
},
"topKeywords": [],
"intentTrends": [],
"callsByIntent": {}
},
"resolutionAnalysis": {
"totalCalls": 450,
"analyzedCalls": 450,
"overallResolutionRate": 78,
"firstCallResolutionRate": 71,
"resolutionDistribution": {
"full": {
"count": 300,
"percentage": 67
},
"partial": {
"count": 52,
"percentage": 12
},
"unresolved": {
"count": 98,
"percentage": 22
}
},
"escalationMetrics": {
"totalEscalations": 31,
"escalationRate": 7,
"byReason": {}
},
"followUpMetrics": {
"totalFollowUpsRequired": 64,
"followUpRate": 14,
"byType": {}
},
"resolutionByIntent": {},
"callsByResolution": {
"resolved": [],
"unresolved": []
}
},
"qualityMetrics": {
"avgSentimentScore": 0.38,
"sentimentDistribution": {
"positive": 58,
"neutral": 34,
"negative": 8
},
"avgClarityScore": 0,
"avgEffectivenessScore": 0,
"avgRapportScore": 0,
"avgConfidence": 0
},
"lastUpdated": "2024-01-31T18:00:00.000Z"
}

List campaign runs#

Every attempt this campaign has made, newest first. A run is what calls and analytics are attributed to, so this is how you compare one attempt with another.

GET/api/v1/campaigns/{id}/runs

Path parameters

idstringrequired
Campaign id.

Query parameters

pagenumber
Page number.
Default1
pageSizenumber
Runs per page, at most 100.
Default20

Responses

A page of runs. `triggeredBy` is the email of whoever started it, if a person did.

curl -X GET "https://voice.evryhealth.com/api/v1/campaigns/{id}/runs" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"runs": [
{
"id": "0f6d2a8e-1d0c-4b7a-9d55-2f1b6a3c9e10",
"campaignId": "357b188c-c618-4f95-84b1-cbe26b8ce3e0",
"runNumber": 3,
"status": "completed",
"startedAt": "2024-01-20T09:00:00.000Z",
"completedAt": "2024-01-20T14:12:00.000Z",
"contactsAttempted": 500,
"contactsReached": 351,
"triggerType": "manual",
"triggeredBy": "ops@example.com"
}
],
"pagination": {
"page": 1,
"pageSize": 20,
"total": 3,
"totalPages": 1
}
}

Get run analytics#

One attempt, in the same shape as campaign analytics.

GET/api/v1/campaigns/{id}/runs/{runId}/analytics

Path parameters

idstringrequired
Campaign id.
runIdstringrequired
Run id.

Responses

The run's analytics.

curl -X GET "https://voice.evryhealth.com/api/v1/campaigns/{id}/runs/{runId}/analytics" \
-H "Authorization: Bearer YOUR_API_KEY"
Response200
{
"campaign": {
"id": "357b188c-c618-4f95-84b1-cbe26b8ce3e0",
"name": "Q1 Provider Outreach",
"status": "active",
"direction": "outbound"
},
"run": {
"id": "0f6d2a8e-1d0c-4b7a-9d55-2f1b6a3c9e10",
"runNumber": 3,
"status": "completed",
"startedAt": "2024-01-20T09:00:00.000Z",
"contactsAttempted": 500,
"contactsReached": 351
},
"metrics": {
"callStats": {
"totalCalls": 1200,
"completedCalls": 1032,
"failedCalls": 96,
"ongoingCalls": 2,
"queuedCalls": 70,
"cancelledCalls": 12,
"analyzedCalls": 1010,
"analysisProgress": 84
},
"successMetrics": {
"humanContactRate": 71,
"humanContactCount": 717,
"objectiveSuccessRate": 0,
"ivrEscapeRate": 0,
"ivrEscapeCount": 0,
"completionRate": 86
},
"qualityMetrics": {
"avgSentimentScore": 0.41,
"sentimentDistribution": {
"positive": 61,
"neutral": 32,
"negative": 7
},
"avgClarityScore": 0,
"avgEffectivenessScore": 0,
"avgRapportScore": 0,
"avgConfidence": 0
},
"complianceMetrics": {
"doNotCallCount": 4,
"doNotCallRate": 0,
"legalThreatCount": 0,
"legalThreatRate": 0,
"complianceScore": 96,
"complianceIssues": []
},
"costMetrics": {
"totalCost": 0,
"costPerCompletedCall": 0,
"costPerHumanContact": 0,
"costPerObjectiveAchieved": 0,
"breakdown": {
"llmCost": 0,
"voiceCost": 0,
"telephonyCost": 0
},
"totalTokens": {
"input": 0,
"output": 0
}
},
"performanceMetrics": {
"avgCallDuration": 212,
"avgIvrNavigationTime": 0,
"avgTimeToHuman": 0,
"callDurationDistribution": {
"under30s": 0,
"under1m": 0,
"under3m": 0,
"under5m": 0,
"over5m": 0
}
},
"informationQuality": {
"dataAccuracyRate": 0,
"totalInformationUpdates": 0,
"updatesByField": {},
"callsWithUpdates": 0,
"callsWithUpdatesRate": 0
}
},
"meta": {
"calculatedAt": "2024-01-20T14:12:00.000Z",
"isStale": false,
"analysisProgress": 84
}
}