# Part 4 — Reference

[← Contents](README.md) · Previous: [Part 3 — What the engine sends you](3-webhooks.md) · Next: [Part 5 — Call flow reference](5-flow-reference.md)

Every value the API returns or accepts, every error code, the limits and defaults.

---

## Calls

### `type`
| Value | Call |
|---|---|
| `INCOMING` | Someone called one of the account's numbers |
| `BROADCAST` | A quick call or broadcast call-out (also scheduled callbacks) |
| `CAMPAIGN` | A campaign call-out |
| `OTP` | A code read out (`POST /v1/otp`) |
| `AGENT_CALL` | An agent called someone from the browser (`POST /v1/calls/agent`) |
| `TEST` | A test call |

### `direction`
`INBOUND` (to us) · `OUTBOUND` (from us).

### `status` (live state)
| Value | Means |
|---|---|
| `QUEUED` | Waiting for a free line (call-out pacing, concurrency) |
| `DIALING` | Dialling out |
| `RINGING` | The person's phone is ringing |
| `IN_SCRIPT` | Blocks are running |
| `WAITING` | In a waiting room (for an agent, a reply, an app action) |
| `CONNECTING` | An agent accepted; joining the call |
| `LIVE` | Talking with an agent |
| `ENDED` | Over |

### `result` (how it went)
| Value | Means |
|---|---|
| `HANDLED_BY_SCRIPT` | The flow dealt with it to the end |
| `HANDLED_BY_AGENT` | An agent talked to the caller |
| `HANDLED_BY_AI` | An AI Agent dealt with it |
| `VOICEMAIL` | The caller left a voicemail |
| `MISSED` | Waited for an agent; nobody answered before the give-up time |
| `ABANDONED` | Hung up while waiting for an agent |
| `HUNG_UP_EARLY` | Hung up in the first seconds |
| `REJECTED` | Refused before the flow ran (no flow, suspended, feature off, caller limit, can-call said no) |
| `FAILED` | Something broke (see `endReason`) |
| `ANSWERED` | Outgoing: the person answered |
| `NO_ANSWER` | Outgoing: rang, nobody answered |
| `BUSY` | Outgoing: line busy |
| `DECLINED` | Outgoing: the person rejected the call (SIP 603); never retried |
| `UNREACHABLE` | Outgoing: phone off or out of coverage |
| `INVALID_NUMBER` | Outgoing: the number does not exist |
| `NOT_DIALED` | Outgoing: never dialled (stopped, opted out, refused) |

### `endReason`
| Value | Means |
|---|---|
| `SCRIPT_END` | The flow ended it (Goodbye, an end of the flow) |
| `CALLER_HUNG_UP` | The caller hung up |
| `AGENT_HUNG_UP` | The agent hung up |
| `AI_ENDED` | The AI Agent ended it |
| `WAIT_GAVE_UP` | The waiting room's give-up time passed |
| `MAX_CALL_LENGTH` | `limits.maxCallMinutes` (or the can-call `maxMinutes`) reached |
| `LOOP_GUARD` | `limits.maxBlockVisits` blocks without any input from the caller |
| `NO_INPUT` | The caller never answered |
| `LIMIT` | Refused by a limit or rule before the flow ran |
| `TRANSFER_FAILED` | A transfer could not complete |
| `NETWORK` | The phone network dropped the call |
| `NOT_ANSWERED` | Outgoing: not answered (see `result`, `hangupCause`, `sipStatus`) |
| `SYSTEM_ERROR` | An engine error; the caller heard an apology |
| `LOST_FINAL_NOTIFICATION` | The end was never reported; closed by the engine's clean-up |

### `endedBy`
`CALLER` · `AGENT` · `AI` · `SYSTEM` · `NETWORK` · `UNKNOWN`.

### `handledBy`
`SCRIPT` · `AGENT` · `AI` · `VOICEMAIL`.

---

## Call-outs

| Field | Values |
|---|---|
| `kind` | `BROADCAST` · `CAMPAIGN` |
| `status` | `DRAFT` · `SCHEDULED` · `RUNNING` · `PAUSED` · `COMPLETED` · `STOPPED` · `CANCELLED` (last three are final) |
| `pauseReason` | `PAUSED_BY_CLIENT` (or your text) · `ACCOUNT_SUSPENDED` · `CLIENT_SUSPENDED` · `VERSION_REVOKED` · `FEATURE_OFF` · `CAN_CALL:<reason>` |
| Recipient `status` | `PENDING` · `DIALING` · `DONE` · `SKIPPED` |
| Recipient `result` | A call `result` (above), or `OPTED_OUT` |
| Skipped `reason` (adding people) | `INVALID_NUMBER` · `NOT_TANZANIAN` · `DUPLICATE` · `OPTED_OUT` |

---

## Agents and departments

| Field | Values |
|---|---|
| Agent `status` | `OFFLINE` · `AVAILABLE` · `RINGING` · `BUSY` · `WRAP_UP` · `AWAY` |
| Department `strategy` | `RING_ALL` · `ROUND_ROBIN` |
| Department `ifNobodyOnline` | `WAIT` · `EXIT_NO_ANSWER` |
| Number `ringMode` | `BROWSER` · `MOBILE` · `BROWSER_AND_MOBILE` |
| Desk signal `type` | `ring` · `ring_cancel` · `connecting` |
| `ring_cancel.reason` | `answered_elsewhere` · `caller_left` · `timeout` · `declined` · `not_joined` |

---

## Numbers, accounts, flows, media

| Field | Values |
|---|---|
| Number `status` | `POOL` (owner's, not given out) · `ALLOCATED` (the client app's, free) · `ASSIGNED` (on an account) |
| Number `type` | `REGULAR` · `TOLL_FREE` |
| Account `status` | `ACTIVE` · `SUSPENDED` |
| Account `recording.mode` | `OFF` · `LIVE_PARTS` |
| Flow `direction` | `INCOMING` (start key `call`) · `OUTGOING` (start key `out`) |
| Media `kind` | `UPLOAD` · `RECORDING` · `SYSTEM` |
| Media `status` | `PENDING` · `PROCESSING` · `READY` · `FAILED` |
| Knowledge document `status` | `READY` · `REMOVED` |
| Transcript `status` | `READY` · `FAILED` |
| Transcript `sentiment` | `positive` · `neutral` · `negative` |
| Client app features | `INBOUND` · `CALLOUTS` · `OTP` · `AI` · `NUMBERS` |
| App action param `type` | `text` · `phone` · `money` · `number` · `choice` |
| Languages | `sw` · `en` |
| TTS voices (messages) | `marin` · `coral` · `shimmer` · `sage` · `cedar` · `ash` · `echo` · `ballad` · `verse`; `speed` 0.7–1.5 |

---

## Timeline events

What `GET /v1/calls/{callId}/timeline` can contain (`type`), by area. `data` holds the details.

| Area | Events |
|---|---|
| **Start and end** | `CALL_RECEIVED` (incoming) · `DIALING` · `RINGING` · `ANSWERED` · `NOT_ANSWERED` (with `sipStatus`, `reason`) · `DIAL_FAILED` · `LIMIT` (refused: `kind`) · `SCRIPT_END` · `CALLER_LEFT` · `ENDED` (`result`, `endReason`, `endedBy`) |
| **Flow** | `BLOCK_ENTER` (`type`) · `SAY` (`text`, `voice`) · `PLAY` (audio) · `OUTCOME` (`tag`) · `CONDITION` (`test`, `result`) · `VARIABLE_MISSING` · `LANGUAGE` · `TRANSFER_OUT` / `TRANSFER_IN` (to another flow) · `EXIT_UNCONNECTED` (the call ended at an unwired exit) · `ERROR` (`code`, e.g. `ACTION_UNKNOWN`, `AI_FEATURE_OFF`, `DEPARTMENT_MISSING`) |
| **Caller input** | `KEY` · `INPUT` (Collect: `value`, `valid`, `by`) · `SPEECH` (`text`) · `MATCH` (menu speech → option) · `NO_INPUT` · `NOT_UNDERSTOOD` · `RETRY` (`attempt`) · `LATER` ("call me later" words) · `POLL` · `PICK` · `PICK_MORE` · `PICK_EMPTY` · `ANSWER_FROM_MENU` · `OPTED_OUT` |
| **Schedule call** | `SCHEDULE_HEARD` (`said`, `at`) · `SCHEDULE_CHANGED` · `SCHEDULE_REFUSED` (`reason`) · `CALL_SCHEDULED` (`at`, `script`, `said`) |
| **Waiting room** | `WAIT_START` (`reason`) · `WAIT_UPDATE` · `WAIT_OPTION` (`key`, `exit`) · `WAIT_END` (`seconds`, `gaveUp`) |
| **Agents** | `NOBODY_ONLINE` · `QUEUED` (`department`) · `RING` (`agents`) · `RING_TIMEOUT` · `RING_DECLINED` · `ACCEPTED` (`agent`) · `CONNECTING` · `AGENT_JOINED` · `LIVE_START` · `AGENT_LEFT` · `AGENT_NO_SHOW` · `HOLD` · `UNHOLD` · `TRANSFER` (`from`, `to`) · `AGENT_HANGUP` |
| **Recording** | `RECORDING_NOTICE` · `RECORDING_STARTED` · `VOICEMAIL` (`recorded`) · `RECORDING_READY` (`kind`, `seconds`) · `RECORDING_FAILED` · `TRANSCRIPT_READY` (`language`, `sentiment`) |
| **Integrations** | `REQUEST` · `REQUEST_SENT` · `REQUEST_QUEUED` · `REQUEST_CALLBACK` · `REPLY_NOT_JSON` · `ACTION_REQUESTED` (`name`, `actionId`) · `ACTION_RESULT` (`name`, `outcome`, `late`) |
| **AI Agent** | `AI_VOICE_DISCLOSURE` · `AI_AGENT_START` · `AI_STAGE` · `AI_HEARD` · `AI_SAID` · `AI_TOOL` · `AI_KNOWLEDGE` · `AI_FIELD` · `AI_HANDOVER` · `AI_FAREWELL` · `AI_EXIT` · `AI_ERROR` · `AI_ENDED` · `AI_USAGE` |
| **OTP** | `OTP_SENT` (the code masked: `••••`) · `OTP_READ` |
| **Voice worker** | `WORKER_JOINED` · `WORKER_LEFT` · `WORKER_ERROR` · `WORKER_USAGE` |

New event types may be added; ignore types you don't know.

---

## Error codes

The `code` field of an error response.

### General
| HTTP | `code` | When |
|---|---|---|
| 400 | `BAD_REQUEST` | Invalid JSON; a missing or wrong query parameter; a value not allowed (message says which) |
| 401 | `UNAUTHORIZED` | Missing or invalid API key |
| 403 | `CLIENT_SUSPENDED` | The client app is suspended by the owner |
| 403 | `FEATURE_OFF` | The client app doesn't have the feature: `CALLOUTS` (call-outs, quick calls), `AI` (flows using AI), `OTP`, `NUMBERS` |
| 403 | `CAN_CALL_REFUSED` | The client app's can-call check refused an agent call |
| 404 | `NOT_FOUND` | No such object, or it belongs to another client app |
| 422 | `VALIDATION_FAILED` | Field errors (`data: {"field": "message"}`), a script's error list, or a list of problems |
| 429 | `RATE_LIMITED` | Over the app's requests per second, or too many OTPs to one number |
| 500 | `INTERNAL_ERROR` | An engine bug |

### By area (409 unless noted)
| `code` | Endpoint | Means |
|---|---|---|
| `ACCOUNT_EXISTS` | create account | `externalRef` already used |
| `ACCOUNT_NOT_ACTIVE` | transfer number | The target account is suspended |
| `NUMBER_ALREADY_YOURS` | add number | Already in the client app's numbers |
| `NUMBER_TAKEN` | add number | Another client app has it |
| `NUMBER_ASSIGNED` | assign / remove number | On another account (release it first) / still on an account |
| `NUMBER_NOT_ASSIGNED` | transfer number | Not on an account: assign it instead |
| `SAME_ACCOUNT` | transfer number | Already on that account |
| `NUMBER_BUSY` | release / remove / transfer | A call is in progress on it |
| `NUMBER_IN_CALLOUT` | release / remove / transfer | An open call-out calls from it |
| `DIRECTION_FIXED` | create flow | A flow keeps its direction |
| `VERSION_EXISTS` | push version | Same number, different document |
| `VERSION_NOT_RUNNABLE` | put flow on number | Not approved, or stopped |
| `VERSION_REVOKED` | approve version, create call-out | The version was stopped |
| `SCRIPT_IN_USE` | delete flow | Numbers, call-outs or other flows use it (`data` lists them) |
| `MEDIA_IN_USE` | delete audio | Live flow versions use it (`data.usedBy`) |
| `STORAGE_QUOTA` | upload audio | The account's 500 MB of audio is used |
| `LIST_LOCKED` | add people | The call-out has started |
| `ALREADY_STARTED` | start call-out | Not a draft any more |
| `NO_RECIPIENTS` | start call-out | Nobody to call |
| `NOT_RUNNING` | pause call-out | Only running or scheduled ones |
| `NOT_PAUSED` | resume call-out | Only paused ones |
| `ALREADY_RUNNING` | cancel call-out | Running call-outs are stopped, not cancelled |
| `DEPARTMENT_IN_USE` | delete department | Live flow versions connect to it (`data.usedBy`) |
| `DEPARTMENT_BUSY` | delete department | Callers are waiting in it |
| `AGENT_BUSY` | set status, agent call | The agent is on a call |
| `NOT_RINGING` | accept, decline | The call is not ringing for this agent any more |
| `ALREADY_TAKEN` | accept | Another agent answered |
| `NOT_YOUR_CALL` | hold, unhold, transfer, hang up | The call is not with this agent |
| `ACTION_IN_USE` | register actions | Removing or narrowing an action a flow or call-out uses |
| `ACTION_ALREADY_RESOLVED` | action result | A different answer was already given |
| `ACTION_TIMED_OUT` | action result | Too late: the call took the `timeout` exit |

### Script check codes
`errors[].code` / `warnings[].code` from checking or pushing a flow version. Errors stop the version from being
stored; warnings don't. What each code means and how to fix it: [Part 5 §5.9](5-flow-reference.md#59-check-codes).

| Area | Codes |
|---|---|
| **Structure** | `DIRECTION_MISSING` · `DIRECTION_MISMATCH` · `START_MISSING` · `START_UNKNOWN` · `TOO_MANY_BLOCKS` · `UNKNOWN_BLOCK_TYPE` |
| **Exits** | `EXIT_TARGET_MISSING` (points to no block) · ⚠ `EXIT_UNCONNECTED` (call ends there) · ⚠ `EXIT_UNKNOWN` (not an exit of that block) · `GOTO_TARGET` · `RETRIES` |
| **Messages** | `MESSAGE_MISSING` · `MESSAGE_SOURCE` · `MESSAGE_TEXT` · `MESSAGE_TOO_LONG` · `MEDIA` · `MEDIA_MISSING` · `UNKNOWN_VARIABLE` · `VARS_IN_INCOMING` |
| **Ask blocks** | `MENU_KEY` · `MENU_KEYS` · `MENU_KEY_LANG` · `MENU_OPTION` · ⚠ `OPTION_WITHOUT_WORDS` · `DIGITS` · `PATTERN` · `SAVE_AS` · `POLL_ANSWERS` · `PICK_SOURCE` · `PICK_PAGE` · `ASK_LENGTH` · `VOICEMAIL_LENGTH` |
| **Connect, waiting room** | `DEPARTMENT` · `WAIT_GIVE_UP` · `WAIT_OPTION` · ⚠ `WAIT_OPTIONS_UNANNOUNCED` |
| **Send request** | `REQUEST_URL` · `REQUEST_HTTPS` · `REQUEST_METHOD` · `REQUEST_BODY` · `REQUEST_AUTH` · `REQUEST_MODE` · `REQUEST_TIMEOUT` · `CALLBACK_URL` |
| **App action** | `ACTION` (unknown action or a parameter missing) |
| **Logic** | `CONDITION_TEST` · `TRANSFER_TARGET` · `RETURN_EXIT` · `RETURN_OUTSIDE_SHARED` |
| **Schedule call** | `SCHEDULE_TARGET` (no runnable Outgoing flow by that ref and version) · `SCHEDULE_TIME` (exactly one of `after`, `at`, `ask`) · `SCHEDULE_TRIES` |
| **AI Agent** | `AGENT_START` · `AGENT_MOVE` · `AGENT_TOOL` · `AGENT_FIELD` · `AGENT_KB` · `AI_LANGUAGE` |
| **Features** | `FEATURE_OFF` (only from `POST /v1/scripts/validate`: the block uses AI and the client app has no `AI` feature) |

⚠ = warning.

---

## Limits and defaults

| What | Value |
|---|---|
| Requests per second | per client app, set by the owner (`429` above it) |
| Blocks per flow | 60 · menu keys 10 · retries 3 · text 500 characters |
| Account `limits` defaults | `maxCallMinutes` 15 · `maxWaitSeconds` 300 · `callerCallsPer10Min` 5 · `otpPerDestinationPer10Min` 3 · `voicemailMaxSeconds` 120 · `maxBlockVisits` 25 |
| Account defaults | language `sw` · zone `Africa/Dar_es_Salaam` · hours Mon–Fri 08:00–17:00, Sat 09:00–13:00 · quiet hours 21:00–07:00 · recording `LIVE_PARTS` + notice · `retentionDays` 90 (1–3650) |
| Quick call | 1–1000 people · `maxTries` 1–3 (default 1) · `retryGapSec` 300–86400 (default 300) |
| Call-out | `maxTries` 1–5 (default 1) · `retryGapSec` ≥ 300 (default 3600) · `pacePerMin` 1–600 (default 60) · ≤ 10,000 people per add |
| Scheduled callback | 5 min to 30 days ahead · quiet hours move it forward · ≤ 3 pending per caller · a new one replaces the old for the same flow · needs `CALLOUTS` |
| Department | ring time 10–60 s (20) · wrap-up 0–300 s (0) · missed rings before Away 0–20 (5; 0 = never) |
| Agent | presence grace 30 s · join after accept 15 s · lobby / call tokens 10 min |
| App actions | ≤ 50 · `timeoutSec` 10–1800 (default 120) |
| Audio upload | ≤ 10 MB · ≤ 5 minutes · 500 MB per account |
| Knowledge document | `.txt` `.md` `.pdf` · ≤ 10 MB · text cut at 200,000 characters |
| OTP code | 4–10 digits |
| Stats / exports | ≤ 400 days per request · default last 7 days · CSV ≤ 100,000 rows |
| Webhook retries | 1 min, 5 min, 30 min, 2 h, 6 h, 12 h … until 24 h |
| Can-call check | connect 0.7 s, answer 1.5 s |
| Pages | calls: size default 50 · recipients: default 100, max 500 |
| Numbers that can be called | Tanzanian (`+255`) only |

---

## Glossary

| Term | Meaning |
|---|---|
| **Account** | One business of a client app |
| **Agent** | A person who answers calls (browser or mobile) |
| **App action** | Something only the client app can do (SMS, payment), asked for by a flow |
| **Block** | One step of a flow: say, menu, collect, connect, AI agent… |
| **Call-out** | Calls placed by the engine to a list of people |
| **Can-call check** | The engine asking the client app "may this call happen?" |
| **Client app** | A product built on the engine, with its own API key |
| **Department** | A group of agents a flow connects callers to |
| **Exit** | A named way out of a block (`next`, `noInput`, an option id); wired to the next block in `x` |
| **Flow / script** | What a call does, as blocks; stored in versions |
| **Lobby** | The agent's LiveKit room for ring signals |
| **Opt-out** | A number the account must never call |
| **Outcome tag** | A label a flow puts on a call (`paid`, `callback_scheduled`) for reports |
| **Quiet hours** | Times when no call-outs are made |
| **Recipient** | One person on a call-out |
| **Runnable** | A flow version that may run (approved) |
| **Version** | A frozen copy of a flow; numbers and call-outs point at one |
| **Waiting room** | Music, updates and key options while a caller waits (for an agent, a reply, a payment) |
| **Wrap-up** | Quiet time after a call before an agent is rung again |