Hellou AI · Schema
ai_call_report
What the account's AI phone calls came to over a date range.
Artificial IntelligenceCommunicationsCustomer ServiceWhatsAppSoftware-as-a-Service
Properties
| Name | Type | Description |
|---|---|---|
| range | object | |
| summary | object | |
| transfers | object | From the AI agent asking for a person to a person answering. |
| amd | object | Answering-machine verdicts on calls the AI agent placed. `none` counts answered calls with no verdict. |
| timeseries | array | Calls per period by outcome. |
| end_reasons | array | How calls ended, most frequent first. |
| end_reason_series | array | End reasons per period. |
| breakdown | object | |
| options | object | The account's lines, AI agents and AI voice campaigns, for filtering. |
| min_sample | integer | Engaged calls below which a group is `low_sample`. |
| timezone | string | The IANA time zone the heatmap and the period buckets were computed in. |
| tools | array | |
| sentiment | object | How the caller's mood moved across the report's AI calls. Codes and counts only. |
| heatmap | array | |
| quality | object | |
| undecided | object |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/hellou-ai/json-schema/hellou-ai-ai-call-report-schema.json",
"title": "ai_call_report",
"description": "What the account's AI phone calls came to over a date range.",
"x-generated": "2026-11-11",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/hellou-ai-openapi.json#/components/schemas/ai_call_report",
"type": "object",
"properties": {
"range": {
"type": "object",
"properties": {
"since": {
"type": "integer",
"description": "Start of the range, unix seconds."
},
"until": {
"type": "integer",
"description": "End of the range (exclusive), unix seconds."
}
},
"required": [
"since",
"until"
]
},
"summary": {
"$ref": "#/$defs/ai_call_report_kpis"
},
"transfers": {
"type": "object",
"description": "From the AI agent asking for a person to a person answering.",
"properties": {
"requested": {
"type": "integer",
"description": "Calls on which the AI agent asked for a person."
},
"parked": {
"type": "integer",
"description": "Calls whose case was registered for a call back because the area was closed; the caller stayed with the AI agent."
},
"attempted": {
"type": "integer",
"description": "Calls a transfer was tried on."
},
"connected": {
"type": "integer",
"description": "Transfers the phone system took."
},
"answered": {
"type": "integer",
"description": "Transfers a person answered."
},
"not_answered": {
"type": "integer",
"description": "Transfers nobody answered (no answer, busy or failed)."
},
"unknown": {
"type": "integer",
"description": "Transfers whose result was not reported."
},
"failed": {
"type": "integer",
"description": "Transfers that could not be placed."
},
"answer_rate": {
"type": [
"number",
"null"
],
"description": "Percent of connected transfers a person answered."
},
"by_area": {
"type": "array",
"items": {
"type": "object",
"properties": {
"area": {
"type": [
"string",
"null"
],
"description": "The area as the AI agent's route names it; `null` for a supervisor's take-over or a transfer with no area."
},
"attempted": {
"type": "integer"
},
"connected": {
"type": "integer"
},
"answered": {
"type": "integer"
},
"failed": {
"type": "integer"
}
},
"required": [
"area",
"attempted",
"connected",
"answered",
"failed"
]
}
},
"by_target": {
"type": "array",
"description": "Internal routing targets only; phone numbers and SIP URIs are never included.",
"items": {
"type": "object",
"properties": {
"type": {
"type": [
"string",
"null"
],
"enum": [
"extension",
"hunt_group",
"softphone",
null
]
},
"value": {
"type": [
"string",
"null"
]
},
"attempted": {
"type": "integer"
},
"connected": {
"type": "integer"
},
"answered": {
"type": "integer"
},
"failed": {
"type": "integer"
}
},
"required": [
"type",
"value",
"attempted",
"connected",
"answered",
"failed"
]
}
}
},
"required": [
"requested",
"parked",
"attempted",
"connected",
"answered",
"not_answered",
"unknown",
"failed",
"answer_rate",
"by_area",
"by_target"
]
},
"amd": {
"type": "object",
"description": "Answering-machine verdicts on calls the AI agent placed. `none` counts answered calls with no verdict.",
"properties": {
"human": {
"type": "integer"
},
"machine": {
"type": "integer"
},
"notsure": {
"type": "integer"
},
"hangup": {
"type": "integer"
},
"none": {
"type": "integer"
}
},
"required": [
"human",
"machine",
"notsure",
"hangup",
"none"
]
},
"timeseries": {
"type": "array",
"description": "Calls per period by outcome.",
"items": {
"type": "object",
"properties": {
"timestamp": {
"type": "integer",
"description": "Start of the period, unix seconds."
},
"calls": {
"type": "integer"
},
"contained": {
"type": "integer"
},
"escalated": {
"type": "integer"
},
"voicemail": {
"type": "integer"
},
"screening": {
"type": "integer"
},
"unanswered": {
"type": "integer"
},
"unreachable": {
"type": "integer"
},
"unknown": {
"type": "integer"
},
"error": {
"type": "integer"
}
},
"required": [
"timestamp",
"calls",
"contained",
"escalated",
"voicemail",
"screening",
"unanswered",
"unreachable",
"unknown",
"error"
]
}
},
"end_reasons": {
"type": "array",
"description": "How calls ended, most frequent first.",
"items": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "The end reason code (for example `contact_hangup`, `transferred`, `max_duration`)."
},
"count": {
"type": "integer"
}
},
"required": [
"reason",
"count"
]
}
},
"end_reason_series": {
"type": "array",
"description": "End reasons per period.",
"items": {
"type": "object",
"properties": {
"timestamp": {
"type": "integer"
},
"counts": {
"type": "object",
"additionalProperties": {
"type": "integer"
}
}
},
"required": [
"timestamp",
"counts"
]
}
},
"breakdown": {
"type": "object",
"properties": {
"bots": {
"type": "array",
"items": {
"$ref": "#/$defs/ai_call_report_row"
}
},
"lines": {
"type": "array",
"items": {
"$ref": "#/$defs/ai_call_report_row"
}
}
},
"required": [
"bots",
"lines"
]
},
"options": {
"type": "object",
"description": "The account's lines, AI agents and AI voice campaigns, for filtering.",
"properties": {
"lines": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": [
"string",
"null"
]
},
"phone_number": {
"type": "string"
}
},
"required": [
"id",
"name",
"phone_number"
]
}
},
"bots": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"name"
]
}
},
"campaigns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"title": {
"type": "string"
},
"timezone": {
"type": "string",
"description": "The campaign's own IANA time zone, for reading the report in it."
}
},
"required": [
"id",
"title",
"timezone"
]
}
},
"evaluation_criteria": {
"type": "array",
"description": "The objectives (post-call goals) of the AI agents that answer the account's lines, by name; use `id` as `evaluation_id`.",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"id",
"name"
]
}
}
},
"required": [
"lines",
"bots",
"campaigns",
"evaluation_criteria"
]
},
"min_sample": {
"type": "integer",
"description": "Engaged calls below which a group is `low_sample`."
},
"timezone": {
"type": "string",
"description": "The IANA time zone the heatmap and the period buckets were computed in."
},
"tools": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"calls": {
"type": "integer"
},
"errors": {
"type": "integer"
},
"error_rate": {
"type": [
"number",
"null"
]
},
"p50_ms": {
"type": [
"number",
"null"
]
},
"p95_ms": {
"type": [
"number",
"null"
]
}
},
"required": [
"name",
"calls",
"errors",
"error_rate",
"p50_ms",
"p95_ms"
]
}
},
"sentiment": {
"type": "object",
"description": "How the caller's mood moved across the report's AI calls. Codes and counts only.",
"properties": {
"measured_calls": {
"type": "integer",
"description": "Calls whose closing mood was read."
},
"unknown_calls": {
"type": "integer",
"description": "Calls without a closing reading, counted apart and left out of every denominator."
},
"opened_negative": {
"type": "integer"
},
"closing_negative": {
"type": "integer"
},
"recovered": {
"type": "integer",
"description": "Calls that started negative and did not end negative."
},
"worsened": {
"type": "integer",
"description": "Calls that did not start negative and ended negative."
},
"recovery_rate": {
"type": [
"number",
"null"
],
"description": "Percent of the calls that opened negative and recovered."
},
"worsening_rate": {
"type": [
"number",
"null"
],
"description": "Percent of the calls that did not open negative and worsened."
},
"positive_rate": {
"type": [
"number",
"null"
],
"description": "Percent of the calls read that ended positive."
},
"negative_rate": {
"type": [
"number",
"null"
],
"description": "Percent of the calls read that ended negative."
},
"net_score": {
"type": [
"number",
"null"
],
"description": "positive_rate minus negative_rate, from the rounded rates."
},
"low_sample": {
"type": "boolean",
"description": "Fewer calls read than min_sample; say the numbers are too few to judge."
},
"opening": {
"type": "object",
"description": "How calls opened: positive, neutral and negative counts.",
"additionalProperties": {
"type": "integer"
}
},
"closing": {
"type": "object",
"description": "How calls ended: positive, neutral and negative counts.",
"additionalProperties": {
"type": "integer"
}
},
"frustration": {
"type": "object",
"description": "Peak frustration per call: calm, annoyed, frustrated and hostile counts, plus `none` for calls whose signals were read but recorded no peak, so the counts add up to `flags_measured_calls`.",
"additionalProperties": {
"type": "integer"
}
},
"wants_human": {
"type": "integer"
},
"churn_risk": {
"type": "integer"
},
"abuse": {
"type": "integer"
},
"attention": {
"type": "integer"
},
"urgency_high": {
"type": "integer"
},
"peak_negative": {
"type": "integer"
},
"flags_measured_calls": {
"type": "integer",
"description": "Calls with a durable signal summary; the signals' own coverage."
},
"matrix": {
"type": "object",
"description": "opening mood -> closing mood -> calls.",
"additionalProperties": {
"type": "object",
"additionalProperties": {
"type": "integer"
}
}
},
"by_outcome": {
"type": "array",
"items": {
"$ref": "#/$defs/ai_call_report_sentiment_breakdown"
}
},
"by_direction": {
"type": "array",
"items": {
"$ref": "#/$defs/ai_call_report_sentiment_breakdown"
}
},
"by_bot": {
"type": "array",
"items": {
"$ref": "#/$defs/ai_call_report_sentiment_breakdown"
}
},
"timeseries": {
"type": "array",
"description": "Calls per period by closing mood, `unknown` included.",
"items": {
"type": "object",
"properties": {
"timestamp": {
"type": "integer",
"description": "Start of the period, unix seconds."
},
"positive": {
"type": "integer"
},
"neutral": {
"type": "integer"
},
"negative": {
"type": "integer"
},
"unknown": {
"type": "integer"
}
},
"required": [
"timestamp",
"positive",
"neutral",
"negative",
"unknown"
]
}
},
"attention_calls": {
"type": "array",
"description": "The latest calls that ended negative or raised an attention flag. Codes only: no transcript and no phone number.",
"items": {
"type": "object",
"properties": {
"call_id": {
"type": "integer"
},
"conversation_id": {
"type": [
"integer",
"null"
]
},
"created_at": {
"type": "integer",
"description": "Unix seconds."
},
"bot_name": {
"type": [
"string",
"null"
]
},
"direction": {
"type": "string",
"enum": [
"inbound",
"outbound"
]
},
"outcome": {
"type": "string",
"enum": [
"contained",
"escalated",
"voicemail",
"screening",
"unanswered",
"unreachable",
"unknown",
"error"
]
},
"opening": {
"type": "string",
"enum": [
"negative",
"neutral",
"positive",
"unknown"
]
},
"closing": {
"type": "string",
"enum": [
"negative",
"neutral",
"positive",
"unknown"
]
},
"peak_frustration": {
"type": [
"string",
"null"
]
},
"wants_human": {
"type": "boolean"
},
"duration_seconds": {
"type": "integer"
}
},
"required": [
"call_id",
"conversation_id",
"created_at",
"bot_name",
"direction",
"outcome",
"opening",
"closing",
"peak_frustration",
"wants_human",
"duration_seconds"
]
}
}
},
"required": [
"measured_calls",
"unknown_calls",
"opened_negative",
"closing_negative",
"recovered",
"worsened",
"recovery_rate",
"worsening_rate",
"positive_rate",
"negative_rate",
"net_score",
"low_sample",
"opening",
"closing",
"frustration",
"wants_human",
"churn_risk",
"abuse",
"attention",
"urgency_high",
"peak_negative",
"flags_measured_calls",
"matrix",
"by_outcome",
"by_direction",
"by_bot",
"timeseries",
"attention_calls"
]
},
"heatmap": {
"type": "array",
"items": {
"type": "object",
"properties": {
"weekday": {
"type": "integer",
"minimum": 0,
"maximum": 6
},
"hour": {
"type": "integer",
"minimum": 0,
"maximum": 23
},
"calls": {
"type": "integer"
}
},
"required": [
"weekday",
"hour",
"calls"
]
}
},
"quality": {
"type": "object",
"properties": {
"interruptions": {
"type": [
"number",
"null"
]
},
"interruption_measured_calls": {
"type": "integer"
},
"silence_ms": {
"type": [
"number",
"null"
]
},
"observed_audio_ms": {
"type": [
"number",
"null"
]
},
"metrics": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"enum": [
"turn_latency_ms",
"llm_sentence_ms",
"first_audio_ms",
"first_turn_start_ms",
"transfer_answer_ms"
]
},
"samples": {
"type": "integer"
},
"p50": {
"type": [
"number",
"null"
]
},
"p95": {
"type": [
"number",
"null"
]
}
},
"required": [
"key",
"samples",
"p50",
"p95"
]
}
},
"evaluated_calls": {
"type": "integer",
"description": "Calls in scope whose goals were checked."
},
"evaluations": {
"type": "array",
"description": "One row per objective: each one a call was judged on plus each one the in-scope AI agents list, so an objective nobody has judged yet shows zero counts.",
"items": {
"type": "object",
"properties": {
"criterion": {
"type": "string",
"description": "The objective's id."
},
"name": {
"type": "string",
"description": "The objective's name; its id when no AI agent lists it any more."
},
"prompt": {
"type": [
"string",
"null"
],
"description": "What the objective asks the AI agent to check; null when no AI agent lists it any more."
},
"deleted": {
"type": "boolean",
"description": "No AI agent in scope lists this objective any more; past calls keep their result."
},
"success": {
"type": "integer"
},
"failure": {
"type": "integer"
},
"uncertain": {
"type": "integer",
"description": "Calls judged below the confidence threshold. Never counted in `success_rate` and never as `unknown`."
},
"unknown": {
"type": "integer",
"description": "Calls that could not be judged, mostly because the call never reached the point the goal is about."
},
"applied_calls": {
"type": "integer",
"description": "Calls where the objective was judged: `success` + `failure` + `uncertain`. `0` means not applicable in this scope."
},
"measured_calls": {
"type": "integer",
"description": "Calls the objective was checked on: `applied_calls` + `unknown` (could not tell)."
},
"success_rate": {
"type": [
"number",
"null"
],
"description": "Percent met among the calls with a confident verdict: `success` / (`success` + `failure`). Null when there are none."
},
"met_rate": {
"type": [
"number",
"null"
],
"description": "Percent of the checked calls where the objective was met: `success` / `measured_calls`. Counts uncertain and could-not-tell calls in the base. Null when `applied_calls` is 0."
}
},
"required": [
"criterion",
"name",
"prompt",
"deleted",
"success",
"failure",
"uncertain",
"unknown",
"applied_calls",
"measured_calls",
"success_rate",
"met_rate"
]
}
},
"audio_timing": {
"type": "object",
"description": "How many of the calls could have the per-turn audio timings (`turn_latency_ms`, `first_audio_ms`, `silence_ms`). Calls on the premium voices are hosted by their engine, which does not report those timings: they count as `unmeasured_calls`, and those rows mean “not measured on this engine” for them, not a missing or zero value.",
"properties": {
"measured_calls": {
"type": "integer",
"description": "Calls whose engine times the audio."
},
"unmeasured_calls": {
"type": "integer",
"description": "Calls on the premium voices, whose engine does not report audio timings."
}
},
"required": [
"measured_calls",
"unmeasured_calls"
]
}
},
"required": [
"interruptions",
"interruption_measured_calls",
"silence_ms",
"observed_audio_ms",
"metrics",
"evaluated_calls",
"evaluations",
"audio_timing"
]
},
"undecided": {
"$ref": "#/$defs/undecided_calls"
}
},
"required": [
"range",
"summary",
"transfers",
"amd",
"timeseries",
"end_reasons",
"end_reason_series",
"breakdown",
"options",
"min_sample",
"timezone",
"tools",
"sentiment",
"heatmap",
"quality",
"undecided"
],
"$defs": {
"ai_call_report_kpis": {
"type": "object",
"description": "The AI call numbers for the whole range, or for one AI agent or line.",
"properties": {
"calls": {
"type": "integer",
"description": "Finished AI calls."
},
"answered": {
"type": "integer",
"description": "Calls someone or a machine picked up."
},
"engaged": {
"type": "integer",
"description": "Calls with a caller (`contained` + `escalated`)."
},
"contained": {
"type": "integer",
"description": "Calls the AI agent finished on its own."
},
"escalated": {
"type": "integer",
"description": "Calls on which the AI agent asked for a person."
},
"transferred": {
"type": "integer",
"description": "Calls transferred to people."
},
"transfer_answered": {
"type": "integer",
"description": "Transferred calls a person answered."
},
"taken_over": {
"type": "integer",
"description": "Calls a supervisor took over."
},
"voicemail": {
"type": "integer",
"description": "Calls an answering machine took."
},
"screening": {
"type": "integer",
"description": "Calls a call screener answered."
},
"unanswered": {
"type": "integer",
"description": "Calls nobody was on the line for: busy, declined, phone off or rang out."
},
"unreachable": {
"type": "integer",
"description": "Calls to a number that does not exist, has no route or was rejected by the carrier."
},
"unknown": {
"type": "integer",
"description": "Calls whose last event never arrived, so the outcome is not known."
},
"errors": {
"type": "integer",
"description": "Calls that ended because of a failure on our side or the voice platform's: the dial, the accept or the sideband failed."
},
"follow_ups": {
"type": "integer",
"description": "Calls that sent a WhatsApp follow-up (sent, delivered, read or replied)."
},
"avg_duration_secs": {
"type": [
"integer",
"null"
],
"description": "Average talk time of answered calls, in seconds."
},
"minutes": {
"type": "number",
"description": "AI minutes of answered calls (standard + premium), two decimals."
},
"standard_minutes": {
"type": "number",
"description": "AI minutes on standard voices."
},
"premium_minutes": {
"type": "number",
"description": "AI minutes on premium voices."
},
"containment_rate": {
"type": [
"number",
"null"
],
"description": "Percent of engaged calls that were contained."
},
"transfer_rate": {
"type": [
"number",
"null"
],
"description": "Percent of engaged calls that were transferred."
},
"transfer_answer_rate": {
"type": [
"number",
"null"
],
"description": "Percent of transferred calls a person answered."
},
"voicemail_rate": {
"type": [
"number",
"null"
],
"description": "Percent of calls an answering machine took."
},
"error_rate": {
"type": [
"number",
"null"
],
"description": "Percent of calls that ended in an error."
},
"low_sample": {
"type": "boolean",
"description": "Fewer engaged calls than `min_sample`; too few to judge."
}
},
"required": [
"calls",
"answered",
"engaged",
"contained",
"escalated",
"transferred",
"transfer_answered",
"taken_over",
"voicemail",
"screening",
"unanswered",
"unreachable",
"unknown",
"errors",
"follow_ups",
"avg_duration_secs",
"minutes",
"standard_minutes",
"premium_minutes",
"containment_rate",
"transfer_rate",
"transfer_answer_rate",
"voicemail_rate",
"error_rate",
"low_sample"
]
},
"ai_call_report_row": {
"description": "One AI agent's or one line's AI call numbers.",
"allOf": [
{
"$ref": "#/$defs/ai_call_report_kpis"
},
{
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "The AI agent's or the line's id."
},
"name": {
"type": [
"string",
"null"
],
"description": "Its name; `null` when it has none or was deleted."
},
"phone_number": {
"type": [
"string",
"null"
],
"description": "The line's number (lines only)."
}
},
"required": [
"id",
"name"
]
}
]
},
"ai_call_report_sentiment_breakdown": {
"type": "object",
"description": "One row of a sentiment breakdown, by outcome, AI agent or direction.",
"properties": {
"outcome": {
"type": "string",
"enum": [
"contained",
"escalated",
"voicemail",
"screening",
"unanswered",
"unreachable",
"unknown",
"error"
]
},
"direction": {
"type": "string",
"enum": [
"inbound",
"outbound"
]
},
"id": {
"type": "integer",
"description": "The AI agent's id, on the `by_bot` breakdown."
},
"name": {
"type": [
"string",
# --- truncated at 32 KB (34 KB total) ---
# Full source: https://artifacts.apis.io/hellou-ai/json-schema/hellou-ai-ai-call-report-schema.json
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/hellou-ai-ai-call-report"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.