Multi-Step Form with Confirmation
A real production-shape form: tabbed sections, prefill from a CRM lookup using a query string token, and a confirmation dialog that runs a separate workflow to compute a summary before the user finally submits. Three workflows wired together by a single form trigger.
This is the recipe for form sections, prefill workflows, and confirmation workflows — three of the most distinctive form features stacked into one signup flow.
Workflow JSON
Section titled “Workflow JSON”Four files. Build them in order — paste each into a fresh workflow with Cmd+V, save, and copy the workflow ID for the next step.
1. Prefill workflow
Section titled “1. Prefill workflow”Runs before the form renders. Looks up the customer in the CRM by URL token and returns a formPrefill object with field overrides. See Return step → Form Prefill Response for the full override schema.
{ "name": "Customer Signup — Prefill", "initial": { "token": "abc123" }, "steps": [ { "stepId": "lookup-customer", "stepType": "core.http", "input": { "url": "https://api.crm.example.com/customers/by-token/{{ initial.token }}", "method": "GET", "connection": "my-crm-api" } }, { "stepId": "respond", "stepType": "core.return", "input": { "formPrefill": { "fields": { "first_name": { "default": "{{ lookup-customer.body.firstName }}" }, "last_name": { "default": "{{ lookup-customer.body.lastName }}" }, "email": { "default": "{{ lookup-customer.body.email }}", "readonly": true }, "company_name": { "default": "{{ lookup-customer.body.company }}" }, "plan": { "enum": "{{ lookup-customer.body.allowedPlans }}", "default": "{{ lookup-customer.body.recommendedPlan }}" } }, "meta": { "title": "Welcome back, {{ lookup-customer.body.firstName }}" } } } } ]}Save this workflow and copy its workflow ID — you’ll need it in step 4.
2. Confirmation workflow
Section titled “2. Confirmation workflow”Runs after the user clicks Submit but before the main workflow runs. Calculates a summary and returns it as a formConfirmation object — see Return step → Form Confirmation Response.
{ "name": "Customer Signup — Confirmation", "initial": { "first_name": "Jane", "company_name": "Acme", "plan": "pro" }, "steps": [ { "stepId": "calc-cost", "stepType": "core.set-variable", "input": { "monthlyCost": "{% if initial.plan == 'starter' %}29{% elsif initial.plan == 'pro' %}99{% elsif initial.plan == 'enterprise' %}499{% endif %}", "annualCost": "{% if initial.plan == 'starter' %}290{% elsif initial.plan == 'pro' %}990{% elsif initial.plan == 'enterprise' %}4990{% endif %}" } }, { "stepId": "respond", "stepType": "core.return", "input": { "formConfirmation": { "title": "Confirm your signup", "summary": "{{ initial.first_name }}, please review your details before we provision your account.", "items": [ { "label": "Name", "value": "{{ initial.first_name }} {{ initial.last_name }}" }, { "label": "Email", "value": "{{ initial.email }}" }, { "label": "Company", "value": "{{ initial.company_name }}" }, { "label": "Plan", "value": "{{ initial.plan }}" }, { "label": "Monthly cost", "value": "${{ $vars.monthlyCost }}" }, { "label": "Annual cost", "value": "${{ $vars.annualCost }}", "type": "info" } ], "warningMessage": "Subscriptions are non-refundable after 30 days." } } } ]}Save this workflow and copy its workflow ID too.
3. Main workflow
Section titled “3. Main workflow”The workflow that actually provisions the account once the user has confirmed.
{ "name": "Customer Signup — Main", "steps": [ { "stepId": "create-customer", "stepType": "core.http", "input": { "url": "https://api.crm.example.com/customers", "method": "POST", "connection": "my-crm-api", "body": { "firstName": "{{ initial.first_name }}", "lastName": "{{ initial.last_name }}", "email": "{{ initial.email }}", "company": "{{ initial.company_name }}", "plan": "{{ initial.plan }}" } } }, { "stepId": "respond", "stepType": "core.return", "input": { "formSubmission": { "type": "success", "message": "Welcome aboard, {{ initial.first_name }}!", "description": "Your {{ initial.plan }} account is provisioned. Check your email for next steps.", "data": { "Customer ID": "{{ create-customer.body.id }}", "Plan": "{{ initial.plan }}" }, "actions": [ { "label": "Open dashboard", "url": "https://app.example.com/dashboard", "style": "primary", "mode": "navigate" } ] } } } ]}4. Form trigger config
Section titled “4. Form trigger config”Add a Form trigger to the main workflow with the config below. Replace WORKFLOW_ID_OF_PREFILL_WORKFLOW and WORKFLOW_ID_OF_CONFIRMATION_WORKFLOW with the IDs you copied earlier.
{ "schema": { "type": "object", "properties": { "first_name": { "type": "string", "x-quickforms-label": "First name" }, "last_name": { "type": "string", "x-quickforms-label": "Last name" }, "email": { "type": "string", "format": "email" }, "company_name": { "type": "string", "x-quickforms-label": "Company name" }, "company_size": { "type": "string", "enum": ["1-10", "11-50", "51-200", "200+"] }, "industry": { "type": "string" }, "plan": { "type": "string", "enum": ["starter", "pro", "enterprise"] } }, "required": ["first_name", "last_name", "email", "company_name", "plan"] }, "meta": { "title": "Sign up", "submitButtonText": "Continue", "layout": "standard", "sections": [ { "key": "contact", "label": "Contact Info", "fields": ["first_name", "last_name", "email"] }, { "key": "company", "label": "Company", "fields": ["company_name", "company_size", "industry"] }, { "key": "plan", "label": "Plan", "fields": ["plan"] } ], "prefill": { "workflowId": "WORKFLOW_ID_OF_PREFILL_WORKFLOW", "timeoutMs": 10000 }, "confirmation": { "workflowId": "WORKFLOW_ID_OF_CONFIRMATION_WORKFLOW", "timeoutMs": 10000 } }}Connection needed: a CRM connection (Salesforce, Hubspot, or your own API). Both the prefill workflow and the main workflow use it. Both Salesforce and Hubspot are first-class in QuickFlo’s connections — Salesforce gets automatic OAuth refresh.
Trigger: the form trigger config above goes on the main workflow.
How it works
Section titled “How it works”A new-customer signup form that:
- Prefills the customer’s name, email, and account tier from a CRM lookup using a token in the URL (
?token=abc123). - Splits fields into 3 tabs — Contact Info, Company Details, Plan Selection.
- Confirms before final submission with a calculated summary showing the chosen plan, monthly cost, and any warnings (e.g. “no refunds after 30 days”).
- Provisions the account in the main workflow once the user confirms.
Test it
Section titled “Test it”- Open the form’s public URL with a
?token=...query parameter:https://run.quickflo.app/f/@your-org/customer-signup?token=abc123 - The prefill workflow runs and the form loads with the customer’s name, email, and recommended plan pre-filled.
- Click through the three tabs (Contact Info → Company → Plan) and fill in any remaining fields.
- Click Continue. The confirmation workflow runs and the user sees a dialog with their summary, calculated costs, and warning message.
- Click Confirm. The main workflow runs and provisions the account.
- The user sees the success response with a “Open dashboard” action button.
What to customize first
Section titled “What to customize first”- Add field validation in the confirmation workflow. Before returning
formConfirmation, run acore.ifstep that catches invalid combinations (e.g. enterprise plan + 1-10 company size) and returns an error string inwarningMessageso the user gets a chance to fix it before final submission. - Use the AI Builder to scaffold the prefill schema overrides if you need many of them — describe the lookup logic in plain English and let the AI generate the
formPrefill.fieldsJSON. - Replace the dummy CRM URL with a real Salesforce / Hubspot connection.
Related recipes
Section titled “Related recipes”- Lead Dedupe + Enrich Pipeline — pairs nicely; ingest signed-up leads from forms into a clean data store