# Vector Step Reference

> Every vector step kind, its required fields, its config keys, and how simple and advanced programs are numbered, saved, and exported.

A **vector** is a named, ordered list of steps that a VDN delegates to:
greeting → wait → queue → loop. Steps are 1-indexed and the
TeleQuick gateway interpreter runs them top-down. The Vectors screen
authors the program. The VDN admin form binds a vector to a VDN — a VDN
left vector-less routes direct-to-skill instead.

This page is the field-level reference for the step editor. For the
call-processing model itself see
[PBX and ACD concepts](/modalities/voice/transport-telephony/pbx-acd).

## The step kinds and their required fields

Eleven kinds are selectable. "Required" is what the editor refuses to
save, mirroring the server contract:

| Kind (stored value) | Label | What it does | Required |
| ------------------- | ----- | ------------ | -------- |
| `announcement`   | Announcement   | Play a TTS / audio message | `announcement_text` **or** `config.audio_source` |
| `wait`           | Wait           | Pause N seconds | `wait_seconds` ≥ 0 |
| `queue_to_skill` | Queue to skill | Enqueue the caller to a skill | `skill_id` |
| `check_skill`    | Check skill    | If ≥ N free agents, route; else fall through | `skill_id` + `free_agent_threshold` |
| `route_to_vdn`   | Route to VDN   | Jump into another VDN program | `target_vdn_id` |
| `goto_step`      | Go to step     | Branch / loop to a step number | `goto_step_no` |
| `goto_if`        | Go to if       | Conditional jump on a collected variable | target step number + condition |
| `http_request`   | API call       | Fetch data (e.g. balance) into variables over HTTP | `config.url` |
| `disconnect`     | Disconnect     | Hang up politely | — |
| `busy`           | Busy           | Busy tone + hang up | — |
| `collect_digits` | Collect digits | DTMF capture (legacy IVR overflow) | — |

Every step, whatever its kind, carries the same row shape. Unused
columns stay `null`:

| Field | Type | Used by |
| ----- | ---- | ------- |
| `step_no` | number \| null | Assigned on save from array order (see below). |
| `kind` | step kind | all |
| `skill_id` | uuid \| null | `queue_to_skill`, `check_skill` |
| `target_vdn_id` | uuid \| null | `route_to_vdn` |
| `goto_step_no` | number \| null | `goto_step`, `goto_if` |
| `wait_seconds` | number \| null | `wait` |
| `free_agent_threshold` | number \| null | `check_skill` |
| `announcement_text` | string \| null | `announcement` |
| `config` | jsonb | per-kind extras: `audio_source`, `hearing`, `url`, branch maps |
| `active` | boolean | all — new steps default to active |

New steps are created with kind-appropriate defaults: a `wait` starts at
`5` seconds and a `check_skill` at a `free_agent_threshold` of `1`.
Everything else starts empty.

The `config` jsonb is free-form and the editor keeps it clean: clearing a
field **deletes the key** rather than storing `null` or `""`. Object
values (branch maps) are read back with their values coerced to strings.

## Announcement: prompt clips, TTS text, and say-as

An announcement can be either a recorded clip or synthesised speech, and
the editor accepts either one:

- **Clip** — pick an audio file with the audio source picker. The
  selection is stored as `config.audio_source`.
- **TTS** — type the message into `announcement_text`.

If both are empty, the save fails with
`Step N (Announcement) needs message text or an audio file.` If both are
set, the clip and the text are both persisted; the interpreter prefers
the clip.

The TTS text is paired with a **say-as mode**, stored alongside it in the
step's `config`. The mode tells the interpreter how to render the text
rather than changing the text itself — use it when the string is a number
that must be spoken digit-by-digit or as an amount rather than as a
cardinal number.

## Wait: hearing mode and audio override

`wait_seconds` is the only required field and it must be non-negative. A
zero-second wait is legal; a negative one is rejected with
`Step N (Wait) needs a non-negative seconds value.`

Two optional `config` keys control what the caller hears for the
duration:

| Config key | Effect |
| ---------- | ------ |
| `hearing` | What is played during the pause — hold music, ringback, or silence. |
| `audio_source` | Overrides the default clip for the selected hearing mode. |

Leave both unset to take the deployment default.

## Skill steps: queue and check

`queue_to_skill` enqueues the caller and needs a `skill_id`.

`check_skill` is the conditional form: it needs both a `skill_id` and a
`free_agent_threshold`. If the skill currently has at least that many
free agents, the call routes; otherwise the step falls through to the
next step. This is the idiom for "try the premium queue, else keep
playing the loop".

Both pickers are populated from `adminSkills.list` (first page, 500
rows). `route_to_vdn` targets come from `adminVdns.list` the same way.

## Conditional jumps: goto_step and goto_if

`goto_step` is an unconditional branch or loop. Its target,
`goto_step_no`, is validated in **simple** programs against the current
array length — a target outside `1…N` fails with
`Step N (Go to step) target X is out of range (1–N).` In **advanced**
programs the check is skipped, because targets there are absolute
`step_no` values rather than array positions.

`goto_if` is the conditional form. It jumps to a target step number only
when a condition over a variable collected earlier in the program holds
— typically a variable captured by a `collect_digits` or `http_request`
step. The condition (the variable, the operator, and the comparison
value) is held in the step's `config`; the editor renders the operator
list and the value field for the operator you pick.

Any `goto_if` in the program makes the program advanced. See the next
section for what that locks.

## API call steps and variable capture

An `http_request` step fetches data over HTTP mid-call — an account
balance, an order status — and captures fields from the response into
variables. Its one required field is `config.url`; an empty or
whitespace URL fails with `Step N (API call) needs a URL.`

The captured variables are what later steps consume: a `goto_if` branches
on them, and an `announcement` can speak them back to the caller. The
placeholder form for referencing a variable is shown in the step editor
next to the field that accepts it.

## Collect digits, disconnect, and busy

`collect_digits` captures DTMF. It is the legacy IVR overflow path and
its per-digit branch map lives in `config` as an object of digit →
target. A step with a branch map makes the program advanced.

`disconnect` and `busy` are terminal and have no required fields:
`disconnect` hangs up politely, `busy` returns busy tone and then hangs
up.

## Simple vs advanced programs

Step writes are **bulk replace**. The editor sends the whole ordered
array to `adminVectors.saveSteps` and the server re-numbers the steps
from array order. That is safe only while step numbers are dense and no
step points at an absolute number.

A program is classified as **advanced** when any of the following is
true:

- step numbers are **sparse** (gaps, e.g. `10, 20, 30` — the classic
  Avaya-style numbering that leaves room to insert),
- it contains a `goto_if` step,
- it contains a DTMF branch map.

In an advanced program the editor **locks structural editing**: no
reordering, no renumbering, no insert-by-position. Renumbering from array
order would scramble jump targets that reference absolute step numbers.
Content stays editable — announcement text and clips, skills, VDN
targets, audio overrides, wait durations. Use the flow diagram to inspect
the branching, and the `goto_step` range check no longer applies.

A simple program (dense `1…N` numbering, no conditional jumps, no branch
maps) keeps the full reorder / move / remove toolkit, and the server
renumbers on every save.

## Saving and the unsaved-changes guard

Saving a vector is two writes: the metadata (`code`, `name`,
`description`, `active`) through `adminVectors.create` or
`adminVectors.update`, then the step array through
`adminVectors.saveSteps`. Code and name are both required.

Because the step write replaces the whole program, the drawer guards
against accidental loss. The form fingerprints its state against a
baseline captured when the steps finish loading; while the fingerprint
differs, closing the drawer prompts to discard. A successful save clears
the flag first, so you are never asked to discard the edits you just
persisted.

## The JSON export format

Export writes a JSON document containing the vector's metadata and its
ordered steps, exactly as the editor holds them — one object per step
with the `kind`, the typed columns (`skill_id`, `target_vdn_id`,
`goto_step_no`, `wait_seconds`, `free_agent_threshold`,
`announcement_text`, `active`), and the `config` jsonb verbatim. Sparse
`step_no` values survive the round trip, which is what makes export/import
usable for advanced programs.

Import parses and validates the document before it touches the editor.
Imported steps land in the form **unsaved**, so the per-kind required-field
checks run and you review the program before committing it. Note that
`skill_id` and `target_vdn_id` are ids: a document exported from one org
needs those references re-pointed before it will validate in another.

## Flow diagram and visual builder

Two read-oriented views open from the vector row:

- **Flow diagram** renders the program as a graph, following
  `goto_step`, `goto_if`, and branch-map edges. This is the way to audit
  an advanced program whose structural editing is locked.
- **Visual builder** is a drag-on-canvas editor over the same step
  array, and saves through the same bulk-replace path.

## Related

- [PBX and ACD concepts](/modalities/voice/transport-telephony/pbx-acd) — VDNs, skills, and where vectors sit
- [Telemetry](/platform/telemetry) — the CDR fields a vector-routed call produces
- [Telephony metrics](/glossary/metrics) — ASA, service level, and the queue numbers a vector shapes
