# Send a request and act on its outcome

Create a Formstep request from an n8n workflow, prefill and lock what you already know, then wait for the answer in the same workflow or start another one when a request ends.

## Before you start

You need a [Formstep credential in n8n](https://formstep.io/docs/guides/n8n/connect/) and a published form. To hear back from Formstep, your n8n must be reachable from the internet over HTTPS; see [Install the Formstep node in n8n](https://formstep.io/docs/guides/n8n/install-the-node/). What a request is, and what it can carry, is in [Creating requests](https://formstep.io/docs/requests/creating-requests/).

For a full walkthrough with real payloads, read [Pausing an n8n workflow until the customer confirms their details](https://formstep.io/blog/n8n-wait-for-customer/). For what the node is good for, and how it compares with n8n’s own form, see [Formstep for n8n](https://formstep.io/integrations/n8n/).

## 1. Add the Create request node

Start with the trigger that should send the request, such as a new row in a sheet or a deal marked won in your CRM. The example uses a manual trigger and an **Edit Fields** node named _Supplier_ that holds `supplier_id`, `company_name` and `contact_email`. Click **+** after it, search for **Formstep**, and pick **Create request**.

## 2. Pick the form and the recipient

- **Form** is the form the recipient completes. Pick it from the list, or switch to **By ID** and paste its ID. It must be published.

- **Recipient Email** usually comes from the input, like `{{ $json.contact_email }}`. It is needed for email delivery and for reminders.

![The Create request node: input from Supplier on the left; Form \[Guide\] Supplier onboarding, Recipient Email {{ $json.contact\_email }}, and Values to Send with company\_name and contact\_email mapped from the input; on the right the output with deduplicated true, deliveryStatus not\_requested, externalId supplier-SUP-1042, status pending and a url on form.formstep.io](https://formstep.io/docs/guides/n8n/n8n-create-request.png)

## 3. Prefill and lock what you already know

Once you pick the form, **Values to Send** lists every question you can prefill by its title and [field key](https://formstep.io/docs/requests/field-keys/), like _Company name (company\_name)_. Map the answers you already have; fields left empty are not sent. With **Mapping Column Mode** set to **Map Automatically**, every input field named after a field key is sent.

![Further down the Create request node: Read-Only Field Names or IDs with Company name (company\_name), an empty Documents list, the Wait for the Outcome switch off, and Additional Fields with Delivery None, External ID supplier-{{ $json.supplier\_id }}, Recipient Name Grace Hansen and Test Mode on](https://formstep.io/docs/guides/n8n/n8n-create-request-options.png)

Pick a question under **Read-Only Field Names or IDs** to lock it. Fields marked _· context_ are the form’s hidden fields. If the form has a Documents block, **Documents** takes files from a binary field of the input item. What each of these does is in [Prefill, locked fields and hidden fields](https://formstep.io/docs/requests/creating-requests/#three-buckets).

## 4. Add the options you need

Click **Add Field** under **Additional Fields**:

- **Delivery** decides who sends the link. **Email the Invitation** lets Formstep send the [invitation and reminders](https://formstep.io/docs/requests/invitations-and-reminders/), on Pro and Business. **None**, the default, sends no invitation: a later node sends the request’s `url` by Slack, SMS or your own email tool.

- **Reminders** left out follows the form’s reminder schedule, and those reminders are emailed even when Delivery is None. Add **Reminders** and leave it empty to send none, or enter a schedule like `2d, 5d`, on Pro and Business.

- **External ID** is your own ID for this piece of work, like `supplier-{{ $json.supplier_id }}`. A later workflow can [find the request by it](https://formstep.io/docs/guides/n8n/manage-requests/#find-a-request). Running the node again with the same External ID and the same parameters returns the same request instead of a second one.

- **Test Mode** creates a [test request](https://formstep.io/docs/requests/creating-requests/): nothing is emailed and it counts nowhere.

- **Recipient Name**, **Language**, **Expires At** and **Metadata** are optional.

- **Callback URL** sends the outcome to a URL of your own. To get the outcome back into this workflow, use [Wait for the Outcome](#wait-for-the-outcome) instead.

## 5. Run the node

Click **Execute step**. Formstep creates the request and returns it with its `id`, `status` `pending`, and `url`, the link for the recipient. Map `{{ $json.url }}` into the node that sends it.

> **Running the node creates a real request**
>
> Unless **Test Mode** is on, every run, including **Execute step** in the editor, is a real request: with email delivery the recipient gets the invitation. Turn Test Mode on while you build the workflow. Before you publish, turn it off and change the External ID, because the old one belongs to the test request.

## Act on the outcome

n8n can hear about a request’s outcome in two ways. Both end in a Switch on `approve`, `decline` or `changes`, which needs a [Decision question](https://formstep.io/docs/requests/decisions-and-approvals/) in the form.

| Way | Use it when |
| - | - |
| Wait for the Outcome | The workflow that creates the request should carry on with the answer, holding on to everything it knew before, like the record it was working on. |
| Formstep Trigger | Requests to the form are sent from anywhere: the dashboard, the API, an agent or another workflow. One published workflow handles all of them. |

## Wait for the outcome in the same workflow

Here the workflow that sends the request pauses until the recipient answers, then carries on.

### 1. Turn on Wait for the Outcome

In the **Create request** node, turn on **Wait for the Outcome** and leave **Callback URL** empty. Formstep then calls this execution back when the request ends.

Each execution waits on its own address, so an External ID reused from an earlier execution fails. Include `{{ $execution.id }}` in it, or leave it empty.

### 2. Add a Wait node

Add a **Wait** node right after it, with **Resume** set to **On Webhook Call** and the HTTP method left at `POST`. Set **Limit Wait Time** if you want n8n to give up on its own.

### 3. Branch on the event

Add a **Switch** after the Wait node and compare `{{ $json.body.data.request.outcome }}`. To tell a completed request from an expired or canceled one, compare `{{ $json.body.type }}` with `request.completed`, `request.expired` or `request.canceled`.

On `request.completed`, `{{ $json.body.data.answers.iban }}` reads the confirmed value of one answer. The part after `answers.` is the question’s [field key](https://formstep.io/docs/requests/field-keys/), which stays the same when you retitle, translate or duplicate the question.

Run the workflow. The execution stops at the Wait node until the recipient submits, then resumes down the matching branch:

![A finished execution: When clicking Execute workflow, Create request, Wait for the answer and a Switch named Outcome, all green, with 1 item leaving the approve output](https://formstep.io/docs/guides/n8n/n8n-wait-for-outcome.png)

- A run from the editor waits for a real answer too. Test Mode works here: a test request still resumes the workflow.

- Expiry also resumes the execution, with `request.expired`. Set **Expires At** to end the wait sooner.

- The Wait node relies on its resume address being hard to guess. If that is not enough, use the Formstep Trigger, which checks that every event comes from Formstep.

## Start a workflow from the trigger

### 1. Pick the event

Add a **Formstep Trigger**, pick the credential and the form, and choose one of the request events under **Event**:

| Event | Runs when | Carries |
| - | - | - |
| Request Completed | The recipient submits the form. | The request, the outcome and every answer. |
| Request Expired | The request reaches its expiry date unanswered. | The request only. |
| Request Canceled | Someone cancels the request, from the dashboard, the API or a Cancel request node, or Formstep cancels it because the form was moved to trash. | The request and the cancel reason. |

### 2. Test it with a real request

A test request never starts a request trigger, so send a real one with Delivery set to None, as in [step 5](#run-the-node), and open its link yourself. Then click **Execute step** and submit the form within two minutes.

The event carries a **data.request** object next to the answers. Its `outcome` is `approve`, `decline` or `changes`, and its `externalId` is the ID you set, so you can find the record the request was about.

Expired and canceled events are hard to catch with **Execute step**. Publish the workflow and check **Executions** instead.

### 3. Branch on the outcome

Add a **Switch** node with one routing rule per verdict. Each rule compares `{{ $json.data.request.outcome }}` with a value; turn on **Rename Output** to name the branch after it:

![A Switch node named Outcome: the input shows data › request with outcome approve, externalId approval-8 and the recipient Grace Hansen; the routing rules compare {{ $json.data.request.outcome }} with approve and changes, each with a renamed output](https://formstep.io/docs/guides/n8n/n8n-route-outcome.png)

Branch on `data.request.outcome`. `data.answers.decision` is empty when the request expired or was canceled, so it cannot tell those branches apart. Compare values, never the labels in `data.display`, which change when you rename the option or the recipient answers in another language.

Connect a node to each branch, then **Publish** the workflow. From then on every completed request to the form runs it.

## If nothing runs

- A test request never starts a request trigger, whether it was created with Test Mode on or with **Try it yourself**.

- The trigger listens only to the form you chose in it.

- The workflow is not published, or its credential reaches another workspace. See the checks in [the public link guide](https://formstep.io/docs/guides/n8n/public-link-submissions/#troubleshooting).

- Create request fails with _Formstep calls back HTTPS addresses only_ when your n8n hands out an `http://` address. See [Tell n8n its public address](https://formstep.io/docs/guides/n8n/install-the-node/#public-address).

- The Wait node never resumes when Formstep cannot reach your n8n, for example because the tunnel is down or the proxy blocks `/webhook-waiting/`.

## Next steps

[Look up, remind and cancel requests in n8n](https://formstep.io/docs/guides/n8n/manage-requests/) — Find a request by External ID, remind the recipient, or withdraw it

[Get a manager's approval in n8n](https://formstep.io/docs/guides/n8n/approval-from-a-manager/) — Send a claim to a manager, wait for the decision, route each outcome

[n8n workflow templates](https://formstep.io/workflows/) — Three workflows to import: CRM prefill, PDF reading with AI, and onboarding

[Form templates](https://formstep.io/templates/) — Forms to start from, each with its field keys listed
