Hellou AI · Schema
voice_campaign
A voice campaign. Outbound campaigns dial the contacts of their audience; inbound campaigns put their agents on PBX queues while the agents are available.
Artificial IntelligenceCommunicationsCustomer ServiceWhatsAppSoftware-as-a-Service
Properties
| Name | Type | Description |
|---|---|---|
| id | integer | The campaign's number within the account. Use it in the campaign paths. |
| title | string | |
| description | stringnull | |
| status | string | |
| handler_type | string | Who handles the calls. |
| direction | string | |
| inbound_queue_ids | array | For inbound campaigns, the PBX hunt-group ids its agents are logged in to while available. Empty for outbound campaigns. |
| executor_type | string | Whether a team, one agent, a hand-picked list of agents or an AI agent works the campaign. |
| executor_id | integernull | |
| agent_user_ids | array | The agents on the list when `executor_type` is `agents`. |
| dialer_mode | string | How an outbound campaign places calls. Ignored by inbound campaigns. |
| lines_per_agent | number | Calls placed per free agent on a human outbound power campaign. Only 1 is accepted until multi-line dialing ships; any other value answers 422 (`attributes` lists `lines_per_agent`). |
| retry_after_voicemail | boolean | Whether a contact is called again after a voicemail (`true` by default). With `false`, a voicemail completes the contact with no more attempts and the `voicemail` disposition (or the agent's voicemail |
| max_attempts | integer | Calls to one contact before it is given up. Once the campaign has calls it can only be raised (422 `attempts_lowered`). |
| retry_delay_mins | integer | Minutes before a contact who was not reached is called again. |
| after_call_work_time | integer | Seconds an agent has for wrap-up after each call, from 10 to 3600. A value outside that range answers 422 (`attributes` lists `after_call_work_time`). |
| import_status | string | Where the contact file import is. `importing` while a file uploaded with `contacts/upload_csv` is read, inserted and validated; `failed` when it was refused (`import_error` says why, the contacts are |
| import_error | stringnull | Why the last file import failed, in the language of the request that uploaded it. `null` unless `import_status` is `failed`. |
| import_progress | integernull | While `import_status` is `importing`, how far the validation of the imported contacts is, in percent. `null` before it starts and when idle. |
| total_contacts | integer | |
| contacts_pending | integer | |
| contacts_called | integer | |
| contacts_answered | integer | |
| contacts_completed | integer | |
| contacts_failed | integer | |
| scheduled_at | stringnull | The instant the campaign was scheduled to start, in UTC. It may be in the past: a campaign whose time has come is launched, and keeps the stamp. |
| ends_at | stringnull | When the campaign ends, in UTC, or null when it has no end date. Once it has passed, the campaign completes; a scheduled campaign past it never launches. |
| started_at | stringnull | |
| completed_at | stringnull | |
| archived_at | stringnull | When the campaign was archived, or null while it is not archived. |
| test | boolean | A label only: a test campaign places real calls like any other, and the label only keeps it out of the default lists unless `include_test` is set. It can change only while the campaign is a draft; on |
| voice_line_id | integernull | For an AI voice campaign, the AI phone line whose AI agent places the calls and whose number the contacts see. |
| voice_line | objectnull | |
| program_id | integernull | The voice campaign program this campaign belongs to, or `null`. |
| batch_label | stringnull | The batch of the program this campaign is part of. |
| sweep_number | integernull | Which sweep (pass over the audience) of the batch this campaign is, from 1. |
| callbacks_pending | integer | Contacts waiting for a call back they asked for, due or not. A completed campaign that still holds some is reopened when one falls due; one nobody dialled for 7 days is given up. |
| paused_reason | stringnull | Why the system paused an AI campaign (`ai_minutes_cap`, the AI phone minutes cap was reached), or `null`. Resuming the campaign clears it. |
| ai_settings | object | What the AI agent says and records on this campaign's calls (AI voice campaigns only). |
| consent_attestation | objectnull | Who attested, and when, that the contacts consented to calls from an AI agent (AI voice campaigns). |
| created_at | string | |
| updated_at | string | |
| declared_variables | array | Only on the single-campaign response. The AI agent's variables that the contact file feeds, in the order the agent declares them. Empty for a campaign worked by people. `label` is in the requester's l |
| variable_map | object | Only on the single-campaign response. Which declared variable each column of the contact file feeds, as `{ " |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/hellou-ai/json-schema/hellou-ai-voice-campaign-schema.json",
"title": "voice_campaign",
"description": "A voice campaign. Outbound campaigns dial the contacts of their audience; inbound campaigns put\ntheir agents on PBX queues while the agents are available.\n",
"x-generated": "2026-11-11",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/hellou-ai-openapi.json#/components/schemas/voice_campaign",
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "The campaign's number within the account. Use it in the campaign paths."
},
"title": {
"type": "string"
},
"description": {
"type": [
"string",
"null"
]
},
"status": {
"type": "string",
"enum": [
"draft",
"validating",
"scheduled",
"running",
"paused",
"completed",
"cancelled",
"failed"
]
},
"handler_type": {
"type": "string",
"enum": [
"voice_human",
"voice_ai"
],
"description": "Who handles the calls."
},
"direction": {
"type": "string",
"enum": [
"outbound",
"inbound"
]
},
"inbound_queue_ids": {
"type": "array",
"description": "For inbound campaigns, the PBX hunt-group ids its agents are logged in to while available. Empty for outbound campaigns.",
"items": {
"type": "string"
}
},
"executor_type": {
"type": "string",
"enum": [
"team",
"agent",
"ai_agent",
"agents"
],
"description": "Whether a team, one agent, a hand-picked list of agents or an AI agent works the campaign."
},
"executor_id": {
"type": [
"integer",
"null"
]
},
"agent_user_ids": {
"type": "array",
"description": "The agents on the list when `executor_type` is `agents`.",
"items": {
"type": "integer"
}
},
"dialer_mode": {
"type": "string",
"enum": [
"preview",
"progressive",
"power"
],
"description": "How an outbound campaign places calls. Ignored by inbound campaigns."
},
"lines_per_agent": {
"type": "number",
"minimum": 1,
"maximum": 3,
"default": 1,
"description": "Calls placed per free agent on a human outbound power campaign. Only 1 is accepted until multi-line dialing ships; any other value answers 422 (`attributes` lists `lines_per_agent`)."
},
"retry_after_voicemail": {
"type": "boolean",
"default": true,
"description": "Whether a contact is called again after a voicemail (`true` by default). With `false`, a voicemail completes the contact with no more attempts and the `voicemail` disposition (or the agent's voicemail disposition). Only a real voicemail signal counts: answering-machine detection, or a voicemail disposition from the agent or the AI agent; a billed call without one is retried as before."
},
"max_attempts": {
"type": "integer",
"description": "Calls to one contact before it is given up. Once the campaign has calls it can only be raised (422 `attempts_lowered`)."
},
"retry_delay_mins": {
"type": "integer",
"description": "Minutes before a contact who was not reached is called again."
},
"after_call_work_time": {
"type": "integer",
"description": "Seconds an agent has for wrap-up after each call, from 10 to 3600. A value outside that range answers 422 (`attributes` lists `after_call_work_time`)."
},
"import_status": {
"type": "string",
"enum": [
"idle",
"importing",
"failed"
],
"description": "Where the contact file import is. `importing` while a file uploaded with `contacts/upload_csv` is read, inserted and validated; `failed` when it was refused (`import_error` says why, the contacts are unchanged); `idle` otherwise, including once the contacts are validated."
},
"import_error": {
"type": [
"string",
"null"
],
"description": "Why the last file import failed, in the language of the request that uploaded it. `null` unless `import_status` is `failed`."
},
"import_progress": {
"type": [
"integer",
"null"
],
"minimum": 0,
"maximum": 100,
"description": "While `import_status` is `importing`, how far the validation of the imported contacts is, in percent. `null` before it starts and when idle."
},
"total_contacts": {
"type": "integer"
},
"contacts_pending": {
"type": "integer"
},
"contacts_called": {
"type": "integer"
},
"contacts_answered": {
"type": "integer"
},
"contacts_completed": {
"type": "integer"
},
"contacts_failed": {
"type": "integer"
},
"scheduled_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "The instant the campaign was scheduled to start, in UTC. It may be in the past: a campaign whose time has come is launched, and keeps the stamp."
},
"ends_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When the campaign ends, in UTC, or null when it has no end date. Once it has passed, the campaign completes; a scheduled campaign past it never launches."
},
"started_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"completed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"archived_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When the campaign was archived, or null while it is not archived."
},
"test": {
"type": "boolean",
"description": "A label only: a test campaign places real calls like any other, and the label only keeps it out of the default lists unless `include_test` is set. It can change only while the campaign is a draft; on any other status a change answers 422 `reason: locked_fields`."
},
"voice_line_id": {
"type": [
"integer",
"null"
],
"description": "For an AI voice campaign, the AI phone line whose AI agent places the calls and whose number the contacts see."
},
"voice_line": {
"type": [
"object",
"null"
],
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": [
"string",
"null"
]
},
"phone_number": {
"type": "string"
},
"agent_bot_id": {
"type": "integer"
}
}
},
"program_id": {
"type": [
"integer",
"null"
],
"description": "The voice campaign program this campaign belongs to, or `null`."
},
"batch_label": {
"type": [
"string",
"null"
],
"description": "The batch of the program this campaign is part of."
},
"sweep_number": {
"type": [
"integer",
"null"
],
"description": "Which sweep (pass over the audience) of the batch this campaign is, from 1."
},
"callbacks_pending": {
"type": "integer",
"description": "Contacts waiting for a call back they asked for, due or not. A completed campaign that still holds some is reopened when one falls due; one nobody dialled for 7 days is given up."
},
"paused_reason": {
"type": [
"string",
"null"
],
"enum": [
"ai_minutes_cap",
null
],
"description": "Why the system paused an AI campaign (`ai_minutes_cap`, the AI phone minutes cap was reached), or `null`. Resuming the campaign clears it."
},
"ai_settings": {
"description": "What the AI agent says and records on this campaign's calls (AI voice campaigns only).",
"anyOf": [
{
"$ref": "#/$defs/voice_campaign_ai_settings"
},
{
"type": "null"
}
]
},
"consent_attestation": {
"type": [
"object",
"null"
],
"description": "Who attested, and when, that the contacts consented to calls from an AI agent (AI voice campaigns).",
"properties": {
"user_id": {
"type": "integer"
},
"at": {
"type": "string",
"format": "date-time"
},
"text_version": {
"type": "integer"
}
}
},
"created_at": {
"type": "string",
"format": "date-time"
},
"updated_at": {
"type": "string",
"format": "date-time"
},
"declared_variables": {
"type": "array",
"description": "Only on the single-campaign response. The AI agent's variables that the contact file feeds, in the order the agent\ndeclares them. Empty for a campaign worked by people. `label` is in the requester's language.\n",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"label": {
"type": "string"
},
"type": {
"type": "string",
"description": "The variable's type, for example `string`, `number`, `date`, `boolean` or `enum`."
},
"options": {
"type": "array",
"description": "The allowed values of an `enum` variable.",
"items": {
"type": "string"
}
}
},
"required": [
"key",
"label",
"type",
"options"
]
}
},
"variable_map": {
"type": "object",
"description": "Only on the single-campaign response. Which declared variable each column of the contact file feeds, as\n`{ \"<file header>\": \"<variable key>\" }`: the saved mapping plus, for a variable it does not name, the file\ncolumn whose own name reads as the key (the way a call reads it). Empty for a campaign worked by people.\n",
"additionalProperties": {
"type": "string"
}
}
},
"$defs": {
"voice_campaign_ai_settings": {
"type": "object",
"description": "The settings of an AI voice campaign. Texts may name the call's data: `{{contact.name}}`, `{{contact.first_name}}`,\n`{{campaign.vars.<column>}}` (a column of the uploaded contact list, its header in lower case with\n`_` for spaces), `{{lookup.<key>}}` (the AI agent's pre-call lookup) and `{{call.number}}`.\n",
"properties": {
"opening": {
"type": "object",
"description": "What the AI agent says when the contact answers, per language (`es`, `en`). Empty uses the AI agent's own opening.",
"additionalProperties": {
"type": "string"
}
},
"first_speaker": {
"type": "string",
"enum": [
"",
"agent",
"caller"
],
"description": "Who opens the call. Empty follows the AI agent's own voice section; `agent` makes it speak first, as it does today; `caller` makes it wait for the contact to speak, greet nobody, ask whether it reached the person, and say the recording notice only after that answer."
},
"dispositions": {
"type": "array",
"maxItems": 20,
"description": "The outcomes the AI agent may record. `outcome` decides what the dialer does next; `next_in_group` means the person who answered is not the one the call is for, so the next person of the contact's group is called instead.",
"items": {
"type": "object",
"required": [
"key",
"label",
"outcome"
],
"properties": {
"key": {
"type": "string",
"pattern": "^[a-z][a-z0-9_]{0,39}$"
},
"label": {
"type": "string"
},
"description": {
"type": "string"
},
"outcome": {
"type": "string",
"enum": [
"contacted",
"retry",
"closed",
"do_not_call",
"next_in_group"
]
}
}
}
},
"extraction_fields": {
"type": "array",
"maxItems": 15,
"description": "The facts the AI agent collects during the call.",
"items": {
"type": "object",
"required": [
"key",
"label",
"type"
],
"properties": {
"key": {
"type": "string",
"pattern": "^[a-z][a-z0-9_]{0,39}$"
},
"label": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"string",
"number",
"boolean",
"date",
"enum"
]
},
"options": {
"type": "array",
"description": "The allowed values of an `enum` field.",
"items": {
"type": "string"
}
},
"description": {
"type": "string"
}
}
}
},
"voicemail": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"hang_up",
"leave_message"
]
},
"message": {
"type": "object",
"description": "The message left on a voicemail, per language.",
"additionalProperties": {
"type": "string"
}
}
}
},
"hot_lead": {
"type": "object",
"properties": {
"route_key": {
"type": [
"string",
"null"
],
"description": "The AI agent's handover route an interested contact is transferred to, live."
}
}
},
"ringing_seconds": {
"type": "integer",
"minimum": 15,
"maximum": 60
},
"variable_map": {
"type": "object",
"maxProperties": 50,
"description": "Which column of the contact list feeds each of the AI agent's declared variables, column header to variable key. Columns it does not name are matched by name.",
"additionalProperties": {
"type": "string"
}
},
"whatsapp_follow_up": {
"description": "Overrides any key of the AI agent's WhatsApp follow-up (its voice section's `whatsapp_follow_up`) for this campaign's calls; an empty value follows the AI agent. Check a configuration with `POST /voice_follow_ups/check`.",
"allOf": [
{
"$ref": "#/$defs/voice_follow_up_config"
}
]
}
}
},
"voice_follow_up_config": {
"type": "object",
"description": "The WhatsApp message an AI agent may send after the contact says yes on a phone call. Set on the AI agent's\n`voice` section as `whatsapp_follow_up`; a voice campaign may override any key in its `ai_settings.whatsapp_follow_up`\n(an empty value follows the AI agent). The AI agent never chooses the number, the text or the template: the message\ngoes to the call's number, as set here.\n",
"properties": {
"enabled": {
"type": "boolean",
"description": "Whether the AI agent offers it."
},
"inbox_id": {
"type": [
"integer",
"null"
],
"description": "The WhatsApp inbox that sends it."
},
"template_name": {
"type": "string",
"description": "An approved template of that inbox, with variables in the body only."
},
"template_language": {
"type": "string"
},
"params": {
"type": "object",
"description": "Each body variable of the template and where its value comes from: `contact.first_name`, `contact.name`, `campaign.name`, `campaign.vars.<column>` (a column of the campaign's contact list), `call.direction`, `call.line`, `call.number`, or `literal:<text>`.",
"additionalProperties": {
"type": "string"
}
},
"offer": {
"type": "object",
"description": "What the AI agent says to offer it, per language (`es`, `en`). Must name the business and WhatsApp and must not promise that the message arrives.",
"additionalProperties": {
"type": "string"
}
},
"skip_dispositions": {
"type": "array",
"description": "Campaign outcomes that never get it. The wrong person (`next_in_group`) never does either.",
"items": {
"type": "string"
}
}
}
}
}
}
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-voice-campaign"
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.