Overview
Steps run in order, following the lines down the pipeline from the trigger. Each step reads from and writes to a shared context object that carries data through the pipeline.The Pipeline Canvas
Opening an automation shows its pipeline as a flow diagram you can zoom and pan: the trigger card at the top, then one card per step, joined by lines. A condition splits into two side-by-side branches labelled Then and Otherwise.- Add a step — click the Add step placeholder at the end of the pipeline or of any branch, or the + on a connecting line (Insert step here) to put a step between two others. Then choose the step type.
- Configure a step — click its card to open its settings. The hint in the top-left corner reads “Click a step to configure it. Drag it onto a + to move it.”
- Move a step — drag its card onto a highlighted + or Add step and drop it there.
- Duplicate or delete — each card has Duplicate step and Delete step buttons. You can also select a card and press Delete or Backspace. Deleting a condition asks you to confirm and says how many steps inside its branches go with it. “The change is kept once you save.”
- Minimap — once a pipeline has more than five steps, a minimap appears in the bottom-right corner for getting around.
- “Select a script in the Create Call step before saving.”
- “Add at least one recipient to the email destination.”
- “Add a subject to the email destination.”
- “Complete the condition step before saving.”
Step Types
Transform
Reshape and map data from one format to another. Transforms are typically used to:- Map incoming webhook fields to contact fields before an Upsert Contact step
- Map call results to CRM column identifiers before a Destination step
Example — mapping webhook fields for a contact:
Transform results are written to
mapped.* in the context and are available to all subsequent steps.
Code
Reshape data with a small piece of Python when field mappings are not enough — splitting a name, building a list, tidying a date, or deciding what to write based on several fields at once. Choose Code from the transform dropdown. The Code step is only available to team members with the manage settings permission. Configuration:
Your code goes inside one top-level
def run():. Return True to carry on, False to stop the branch.
Reading and writing the context:
Doing work:
set_call_result(data) — pass a dictionary of your own fields and they are stored on the call, in a field of their own, separate from the AI’s summary and structured data. Use it when the automation, not the model, is the authority on how a call turned out. The values are returned with the call by the API, so reporting can read them directly instead of picking apart a summary. The step must be running on a call — that is, the automation’s trigger is Call Completed or Call Scheduled. Fields are merged in, so a second call adds to what is there rather than replacing everything.
integration_request(...) — read data from a connected integration using the credentials and address already stored against it. You give it a path, not a full web address; an absolute URL is refused, so the stored credentials can never be pointed at another site. It is read-only and paginated, so large collections come back a page at a time. An error from the far end comes back as data rather than stopping the step, which lets a loop set one record aside and keep going.
enqueue_automation(automation_id, payload) — start another automation and hand it a payload, which arrives there as trigger.*. Use it to give each record its own run, so one bad record fails and retries on its own instead of taking the whole batch down with it. You cannot enqueue the automation that is running, an automation in another team, or a disabled one.
Writing the code:
- One top-level
def run():. No nested definitions, no classes, no decorators, no lambdas. - No imports.
- Indent with spaces, not tabs. The editor converts pasted tabs for you and the Tab key inserts four spaces.
- Errors show as you type, each with its line number — for example
Line 12 — Tabs are not allowed, indent with spaces. - There is no attribute access in the sandbox, so build lists by joining them together rather than with
.append.
Going over the 2 MB limit fails that one function call, not the whole run — so page through large reads rather than asking for everything at once. Going over the call or change limits stops the run.
LLM
Ask an AI model to read some data and give you a structured answer — classifying a call, tidying free text, or pulling a few fields out of a long note. Choose LLM from the transform dropdown. Configuration:
Placeholders in the prompt are filled in from the run’s live context before the model sees it —
call.*, contact.* and trigger.* all work — so the prompt can quote the actual transcript, the contact’s details, or the incoming webhook payload rather than being written in the abstract.
Each field in the Output Schema needs a description. It is what tells the model what you actually want, so write it as though you were explaining the field to a new team member.
Upsert Contact
Create a new contact in Voxworks or update an existing one. The step matches on either phone number or email to determine whether to create or update. Configuration:
After this step runs,
contact.* is available in the context for all subsequent steps.
Example:
Match on phone_number, with mappings:
If a contact with that phone number already exists, their name fields are updated. If not, a new contact is created.
Upsert Object
Create or update a typed data object and optionally link it to the contact. Objects store CRM identifiers and external data that your automation needs to reference later — for example, a Monday.com item ID or a HubSpot deal ID. Configuration:
After this step runs, the object’s data is available at
objects.{type_name}.*.
Merge or replace. By default the fields you supply are merged into the record, leaving anything you did not mention untouched. From a Code step you can ask for replace instead, which writes exactly the fields you supply and drops the rest — use it when the incoming data is the whole truth about that record. The name field updates the record’s display name.
Example:
Object type: monday_item, match on CRM_ID = trigger.crm_id, link to contact: yes.
Create Call
Trigger an outbound call using a specific Script. This step creates a call record and schedules it for immediate execution (or at a specified time). Configuration:
Important: Pipeline split. Any steps placed after Create Call become post-call steps. They do not execute until the call finishes and the AI has generated the summary and structured data. On the canvas, the line into the Create Call step is labelled Call started and the line out of it Call completed.
After the call completes,
call.* is populated with the full call record including summary, transcript, structured data, and objectives.
Destination
Push data to an external system. There are four destination types:Integration Sync
Sync data to a connected CRM (e.g., Monday.com). Uses field mappings to map call outputs and object data to integration-specific column identifiers.
The target field names correspond to column IDs in your CRM. You’ll find these in your CRM’s column settings.
{{variable}} interpolation.
Email template. The list has three groups:
- Voxworks system templates — each shown as “<name> — Add to team”. Picking one adds the latest version to your team as an editable copy and uses that copy.
- Team templates — your team’s own designs; the team default is marked — Default.
- One-off custom email — write the subject and body for this step only.
SMS
Send a text message to the contact or to team members.Webhook
Send an HTTP request to any URL. Useful for integrating with systems that don’t have a native integration.Condition
Branch the pipeline based on a field value. If the condition is true, the steps in the Then branch run. If false, the steps in the optional Otherwise branch run (or nothing happens). Configuration:
Example — notify team on low rating:
- Field:
call.structured_data.fields.rating.value - Operator:
lt - Value:
3 - Then: SMS to team — “Low rating call: {{contact.full_name}}”
- Otherwise: (skip)
Source
Fetch data from an external API or connected integration. The response is written tosource.* in the context.
Configuration (HTTP):
Configuration (Integration Fetch):
The fetched data is resolved at runtime using object identifiers from the context (e.g., the contact’s linked CRM item ID).

