---
title: 'Workflow Building Guide'
description: 'The recommended way to build a workflow through the API, start to finish, and the details that trip people and agents up.'
---

This guide is the short path through building a workflow with the API, and the lessons from building many of them. [Build a Workflow](/docs/api/rest/introduction/build-a-workflow) covers each part in more depth, and every endpoint name below links to its reference page.

## The recommended path

1. **Check where you are acting.** [Who Am I?](/docs/api/rest/actions/get-me) answers the organization your requests act on and the permissions your key has there. Every workflow, connection and run you touch belongs to that organization.
2. **Find the apps and actions.** [List Universal Apps](/docs/api/rest/actions/list-universal-apps) finds an app by name (`q=slack`; `includeBuiltins=true` adds Loop, If/Else, Map and the other [built-in steps](/docs/api/rest/introduction/built-in-steps)). [List Universal Actions](/docs/api/rest/actions/list-universal-actions) finds its actions. Use the slugs they answer, such as `list-users` and `send-user-message` for Slack.
3. **Pick a connection.** [List Connections](/docs/api/rest/actions/list-connections) with `app=slack` lists the app's connections, the organization's default first. Use one your key's creator can use: their own personal connections, and the organization's shared ones that the connection's role grants open to them. Another member's personal connection, and a shared one whose role grants leave the creator out, are refused. A connection's `status` is the result of its last sign-in, test or use, so [Test Connection](/docs/api/rest/actions/test-connection) before you rely on one that has not been used lately. No connection yet? [List Connection Fields](/docs/api/rest/actions/list-connection-fields) says what the app asks for: an app that takes an API key is connected with [Create Connection](/docs/api/rest/actions/create-connection); an OAuth app (`requiresBrowser` true) needs your key's creator to sign in through [Create Connect Link](/docs/api/rest/actions/create-connect-link).
4. **Create the workflow** with [Create Workflow](/docs/api/rest/actions/create-workflow), then read its first revision from [Get Workflow Definition](/docs/api/rest/actions/get-workflow-definition).
5. **Build it in one call** with [Set Workflow Definition](/docs/api/rest/actions/set-workflow-definition): every trigger and step, nested as they run, each with its configuration. Give each new step a `ref` and reference it by that ref anywhere in the same body. It is all or nothing, and a refusal lists every problem with its JSON Pointer into your body. Check a body first, without saving it, with [Validate Workflow Definition](/docs/api/rest/actions/validate-workflow-definition).
6. **Set any Map code** that reads a step you just created, in one follow-up [Update Workflow Step Configuration](/docs/api/rest/actions/update-workflow-step-configuration) (see below).
7. **Test** the steps that read data with [Test Workflow Step](/docs/api/rest/actions/test-workflow-step). Its output becomes the sample later steps read.
8. **Validate, publish and turn it on:** [Validate Workflow](/docs/api/rest/actions/validate-workflow), [Publish Workflow](/docs/api/rest/actions/publish-workflow), then `"isActive": true` with [Update Workflow](/docs/api/rest/actions/update-workflow).
9. **Run it** by calling its trigger or with [Run Workflow](/docs/api/rest/actions/run-workflow), and follow it with [Get Run](/docs/api/rest/actions/get-run).
10. **Check what it did** with [List Run Steps](/docs/api/rest/actions/list-run-steps) and [Get a Run Step](/docs/api/rest/actions/get-run-step): the exact request each step sent and what the provider answered.

## What to know

### Revisions

Every change to the draft needs the revision you last read in the `If-Match` header, sent as `"r_..."`; Test Workflow Step is the one exception, where it is optional but recommended. A change answers the new one in `meta.revision`, and the `ETag` header of a draft read or change is the same value, so you can send it straight back. A `412` means someone changed the draft since you read it: read it again and retry.

Most draft changes don't touch what runs: the workflow's triggers run its published version. Three trigger settings are the exception and go live as soon as you save them, as in the editor: a schedule, a webhook's custom URL and a polling interval. Two things also act on the draft right away: [Run Workflow](/docs/api/rest/actions/run-workflow) with `"version": "draft"` runs it, and Test Workflow Step runs one of its steps for real.

### Map steps and input keys

A Map step's code reads each input as `input['<key>']`, and the key ends in the last four characters of the input step's id, in capitals, such as `input['slackListUsers7K2Q']`. A step created in the same Set Workflow Definition call has no id until the call answers, so:

1. add the Map step with its `inputs` and no `code` (it is saved, and shows as not set up yet);
2. read the key from the answer's `inputKeys`;
3. set the code with Update Workflow Step Configuration.

Code that reads a key no input provides gets `undefined` at run time, so Validate Workflow and Publish warn `UNKNOWN_INPUT_KEY`. Read every warning before you publish.

### Paging

An app step that lists records makes one request for the first page only, at the action's default page size, unless you set its `pagination` option. A list longer than one page is cut short without an error. Set `"pagination": { "mode": "all" }` to read every page. An action that pages by size only takes `"mode": "single"` instead, so raise its `size`. [Get Workflow Step Schema](/docs/api/rest/actions/get-workflow-step-schema) gives the modes the action takes and its page sizes, and [Workflow References](/docs/api/rest/introduction/workflow-references) describes each mode.

### Choosing values from the app

When an argument takes a provider id, such as a Slack channel or user, find it by name instead of guessing: [Run Workflow Step Lookup](/docs/api/rest/actions/run-workflow-step-lookup) for a step in a workflow, or [Resolve Universal Lookup](/docs/api/rest/actions/resolve-universal-lookup) for an action on its own. Both take the text to find as `q` (`search` is accepted too).

### Conditions

If/Else conditions and step filters compare text case-sensitively. Use `startsWith`, `endsWith`, `contain` and their opposites for text, and set `type` to `number` or `date` to compare those as numbers or dates. [Workflow References](/docs/api/rest/introduction/workflow-references) lists every operator. A single condition is stored, and read back, as a group of one: `{ "conjunction": "and", "where": [ ... ] }`.

### Real side effects

Test Workflow Step runs the step for real, with its connection: a step that sends a message sends it, and a step that creates a record creates it. Test the steps that read, and give the steps that write a sample with [Update Workflow Step Output](/docs/api/rest/actions/update-workflow-step-output) instead. Running the workflow, or calling its webhook, sends everything it sends, so check [List Runs](/docs/api/rest/actions/list-runs) before you run it again.

### Webhooks

A new Webhook trigger queues each call and answers at once (`waitForCompletion` is `false`). Its default answer includes `runId`, the run that call started, so you can follow it with Get Run. It is `null` when the trigger processes calls in order, since that run starts later, and a trigger set to send a custom response answers that instead, without `runId`. Its address is in [Get Workflow Trigger Configuration](/docs/api/rest/actions/get-workflow-trigger-configuration).
