Skip to main content

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.
A card that isn’t fully set up shows a warning icon, and Save is blocked until it’s fixed. The message names the problem, for example:
  • “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
Configuration: Add one or more field mappings. Each mapping has: 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.
Limits: 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.

Email

Send an email to the contact, your team members, or a specific address. Email subjects and bodies support {{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.
As the hint under the field says: “Selecting a system template adds the latest version to your team as an editable copy. Manage team templates in Settings → Email templates.” Only Post-call templates are offered here. Choosing a template fills the step’s subject and body from it. See Email Templates. Placeholders in the subject and body are filled from the call, the contact and your team, so a post-call email can carry the summary, the collected fields and the contact’s details without any extra mapping. Values that run to several lines keep their line breaks in the branded HTML email, and any characters that would otherwise break the layout are handled for you. Dates and times are shown in your account’s timezone rather than UTC. A placeholder that has no value comes out as an empty string.

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)
A branch can hold another Condition, so conditions can be nested. See Conditions.

Source

Fetch data from an external API or connected integration. The response is written to source.* 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).

Limits