Every automation I have built for a client hits the same wall. The workflow has done its part. Now it needs one thing from a person who is not on the team: a bank detail, a signature, a document. The workflow stops, and someone writes an email.

This post shows a pattern that removes that email. The workflow sends the person a form made for them, waits, and carries on with their answers. I built Formstep for this step, so I will also say when you do not need it.

In short: create a Formstep request, pause on a Wait node, and branch on how the request ended: answered, expired or canceled.

Why not n8n's own form, or a form builder?

Both work well when the person is a colleague, or when the form is for anyone. They get awkward when one outside person has to answer about one record. This is what each tool's docs said on 5 November 2026:

n8n Wait node form Form builder link + webhook Formstep request
Who can answer Anyone with the resume link Anyone with the link, any number of times One named person, once
What you already know Prefill is not in its docs Prefilled through the URL, where it can be read and changed Prefilled on the server. The link carries a token, not the data
Values they must not change Locking is not in its docs Often missing Locked per request
What you can ask for Six field types, no file upload Depends on the builder Files, signatures, payments and 20+ question types
If they go quiet You build the follow-up You build the follow-up Reminders on a schedule (paid plans), then the request expires
How the run continues Same execution A second workflow has to find the record Same execution
What they see Your n8n address The builder's page Your logo and colors, in their language

Answers also come back under field keys you set once, like iban. Rename or translate the question and your workflow still works.

The longer comparisons, with sources, are Formstep vs n8n's form and why not use a form builder.

The pattern: four nodes

A finished n8n execution: a manual trigger, Create request, a Wait node named Wait for the answer, and a Switch named Outcome, all green, with one item leaving the approve output

  1. Trigger. Anything: a new row, a CRM stage, an email.
  2. Create request, from the Formstep node. Pick the form, set the recipient's email, map what you already know, and turn on Wait for the Outcome.
  3. Wait, set to On Webhook Call. The Create request node has already handed Formstep this execution's resume URL, so you never build that URL yourself.
  4. Switch on {{ $json.body.type }}:
    • request.completed: the answers are under {{ $json.body.data.answers }}.
    • request.expired: they never finished.
    • request.canceled: someone withdrew it.

Formstep calls back on every ending, not only on success. So the run never hangs on someone who went quiet. A request expires after 30 days unless you set another date.

The node is n8n-nodes-formstep, MIT-licensed, for self-hosted n8n. The install guide has the steps. On n8n Cloud, call the Formstep REST API from an HTTP Request node and pass the resume URL as the callback URL.

Here are three jobs the same four nodes do.

Use case 1: confirm what you already have

A supplier's bank details sit in a sheet, and you want them confirmed before you pay.

In Create request, map company_name and iban from the sheet under Values to Send. Then pick company_name under Read-Only Field Names or IDs. The supplier opens the link and sees this:

The request form with Company name showing Analytical Engines Ltd in a greyed-out field and the note: Filled in by the sender

They confirm the IBAN or fix it. They cannot change the company name. After the Wait node, {{ $json.body.data.answers.iban }} is the confirmed value.

To start from a ready-made form, use the vendor onboarding template.

Use case 2: AI reads an invoice, the sender checks it

AI reads PDFs well. But when it misreads a digit, it looks just as sure as when it is right. In my own test the model read a total of 27 325 as 27 235, and the execution looked the same as a correct one.

So let the person who sent the invoice check it:

  1. Extract from File pulls the text out of the PDF. A scan has no text, so for scans use a model node that reads images instead.
  2. Information Extractor reads the supplier, invoice number, dates and total.
  3. Create request sends the supplier a form with every value filled in and the invoice shown above it.
  4. After the Wait node, a Code node compares what the AI read with what the supplier confirmed:
const read = $('Read the invoice with AI').item.json.output const confirmed = $json.body.data.answers const corrected = Object.keys(read).filter((key) => String(read[key]) !== String(confirmed[key])) return { json: { invoice: confirmed, corrected } } 

Now you review only the invoices where corrected is not empty, not every invoice.

The full walkthrough is in reading a PDF with AI in n8n, and you can import the finished workflow.

Use case 3: a form built on the fly

Sometimes the questions depend on the case. A water damage claim needs photos and a repair estimate. A theft claim needs a police report and receipts. You do not want to build one form per case.

Keep the checklist in a Code node and send it with the request:

const checklists = { water_damage: [ { key: 'damage_photos', title: 'Photos of the damage', maxFiles: 10 }, { key: 'repair_estimate', title: 'Repair estimate from a contractor', maxFiles: 1 }, ], theft: [ { key: 'police_report', title: 'Police report', maxFiles: 1 }, { key: 'receipts', title: 'Receipts for the stolen items', maxFiles: 10 }, ], } const blocks = checklists[$json.claimType].map((document) => ({ type: 'file', ...document })) return { json: { ...$json, blocks } } 

In Create request, set Form Source to New Form and Form Blocks to {{ JSON.stringify($json.blocks) }}.

Formstep builds the form the first time it sees a definition and reuses it after that. The claimant sees only the uploads their claim needs, and your workflow gets a download URL for each file. A new claim type is a new entry in the object, not a new form.

The full walkthrough is in collecting documents in n8n, and every block type is in the docs.

Three things that bite

  • The resume URL shows localhost. n8n builds it from WEBHOOK_URL, not from your browser. Set it to your public HTTPS address. The Create request node refuses an http:// or private address before it creates anything, so a wrong setting fails while you build.
  • The execution is gone when the answer arrives. The answers live in the request, not in the waiting execution. Read them with Get request, or start a fresh workflow with the Formstep Trigger so nothing has to wait.
  • Testing emails real people. Turn on Test Mode. No email goes out, nothing is counted, and the callback still resumes the Wait node.

What it costs

The node is free. Requests, prefill, locked fields, callbacks and expiry are on every Formstep plan, with 1,000 submissions and requests a month on Free. On Free you send the link yourself. Having Formstep email the invitation and the reminders needs Pro, at $39 a month. The pricing page has the rest.

When n8n's own form is the better choice

If the person is on your team, use n8n's form. It is one fewer service holding your data, colleagues can answer as themselves with n8n User Auth, and it works on n8n Cloud, where the Formstep node does not yet. If you only need a yes or no from someone in Slack, Slack buttons are simpler.

Formstep earns its place when the person is outside your company, the data should arrive filled in or locked, someone has to chase them, and the run has to carry on by itself.

I'm Onur, the founder of Formstep. A longer version of the first pattern is on the Formstep blog.