Create Operator
Create a new operator (human agent) that can be assigned to virtual numbers for inbound call routing.
https://api.identitycall.ai/api/v1/public/operatorsCreate an operator with a name and phone number. Phone numbers are auto-normalized to E.164.
An operator is a person, not a phone line
Do not create one operator per phone number. An agent who answers five lines is still one operator — creating five would split that person’s analytics, agent scoring and voice profile across five records.
phone_number is optional and only matters if you want IdentityCall to
forward live calls from a virtual number to that person, or to guess
attribution from the dialled line. If you send operator_id on upload, you
do not need it at all.
To match your own agents to IdentityCall operators, set external_id to your
employee/CRM id. It is unique per account, so it is a safe match key — names are
not unique, and two people can share neither.
Scope and auto-linking
Project-scoped keys auto-link the new operator to the bound project.
When you create an operator with a project-scoped API key, the operator is created and an OperatorProject row is automatically inserted that links the new operator to the key’s bound project. This makes the operator immediately visible to other project-scoped requests.
When you create an operator with an account-wide key, the operator is created unlinked unless you pass project_id. An unlinked operator still works as an operator_id on uploads, but a project-scoped key will not list it until you link it — see Link Operator to Project.
| API key scope | Behavior |
|---|---|
Account-wide, no project_id | Creates an unlinked account-level operator |
Account-wide, with project_id | Creates the operator and links it to that project |
| Project-scoped | Creates the operator and auto-links it to the bound project |
Request Body
Body Parameters (application/json)
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Full display name (e.g. "Jane Doe"). Used to derive `initials`. |
external_id | string | No | - | Your own stable identifier (employee id, CRM id). Unique per account. Recommended as the match key for roster syncs. |
phone_number | string | No | - | Optional. Unique per account when given. Only needed to forward live calls from a virtual number. Auto-normalized to E.164. |
email | string | No | - | Optional contact email for the operator. |
active | boolean | No | true | Whether the operator can currently receive routed calls. |
project_id | integer | No | - | Link the new operator to this project immediately. Project-scoped keys link to their own project automatically and can omit it. |
Request
cURL
curl -X POST "https://api.identitycall.ai/api/v1/public/operators" \
-H "Authorization: Bearer $IDENTITYCALL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"phone_number": "+15551234567",
"email": "jane.doe@example.com",
"active": true
}'Response
{
"data": {
"id": 42,
"name": "Jane Doe",
"external_id": "crm-4417",
"phone_number": "+15551234567",
"email": "jane.doe@example.com",
"active": true,
"initials": "JD",
"recording_project_ids": [12],
"virtual_numbers": []
}
}Response Fields
| Field | Type | Description |
|---|---|---|
id | integer | Unique operator ID |
name | string | Full display name |
external_id | string | null | Your identifier for this person |
phone_number | string | null | E.164 normalized phone number, or null |
email | string | null | Contact email |
active | boolean | Whether the operator is active |
initials | string | Two-letter initials derived from name |
recording_project_ids | integer[] | Projects this operator is linked to |
virtual_numbers | array | Virtual numbers assigned to this operator (empty on create) |
Each entry of virtual_numbers (when populated later) has the shape:
| Field | Type | Description |
|---|---|---|
id | integer | Virtual number ID |
phone_number | string | The virtual number in E.164 |
name | string | Display name of the virtual number |
active | boolean | Whether the virtual number is active |
Errors
| Status | Error | Description |
|---|---|---|
| 401 | “Invalid API key” | Missing or unrecognized bearer token |
| 403 | “Write permission required” | API key lacks write permission |
| 422 | ["Name can't be blank"] | name was not supplied |
| 422 | ["Phone number is invalid"] | Phone number could not be normalized to a valid E.164 value |
| 422 | ["External has already been taken"] | Another operator in this account already uses that external_id — look it up instead of creating a duplicate |
| 422 | ["Phone number has already been taken"] | Another operator in this account already uses that number — look it up with List Operators instead of creating a duplicate |
| 403 | “project_id does not match this API key’s project” | A project-scoped key named a different project |
| 404 | “Project not found” | project_id is not a project in this account |