Form2Workflow

Getting started

What you can build

Ready-to-copy blueprints: a client portal with Microsoft sign-in, an approval queue, a quote that ends at Stripe checkout, an AI answer page and an order-status lookup.

Each blueprint lists the forms (paste the JSON with update_form, or build them in the editor) and what each n8n workflow does. Replace https://n8n.example.com with your n8n and keep every workflow's Webhook node set to respond with a Respond to Webhook node.

Building with an AI agent? Point it at this page: “Build the client portal blueprint from form2wf's use-cases page in my organization.” The MCP server can create the forms; you wire the n8n side.

Client portal with Microsoft sign-in#

Clients sign in with their work Microsoft account, see their projects and open requests, and file new ones. No accounts to create: access is limited to their company's email domain.

Access: both forms Verified, email domain clientco.com (see Verified). Theme: put both in one folder with a folder theme.

form portal-home (onload: portal-home webhook)
{ "showTitle": false, "fields": [
  { "id": "menu", "type": "nav", "navItems": [
    { "label": "Overview", "form": "portal-home" }, { "label": "New request", "form": "portal-request" } ] },
  { "id": "hello", "type": "markdown",
    "markdown": "## Welcome back, {{data.name}}\n\n{{data.notice}}" },
  { "id": "projects", "type": "table", "label": "Your projects", "dataSource": "projects", "tableSearch": true, "pageSize": 10,
    "columns": [ { "field": "name", "label": "Project" }, { "field": "stage", "label": "Stage" }, { "field": "due", "label": "Due" } ] }
] }
form portal-request (submit: portal-request webhook)
{ "showTitle": false, "fields": [
  { "id": "menu", "type": "nav", "navItems": [
    { "label": "Overview", "form": "portal-home" }, { "label": "New request", "form": "portal-request" } ] },
  { "id": "subject", "type": "text", "name": "subject", "label": "Subject", "required": true },
  { "id": "details", "type": "textarea", "name": "details", "label": "What do you need?", "required": true },
  { "id": "file", "type": "file", "name": "attachment", "label": "Attachment" }
] }
  • portal-home workflow: read body.endUser.email (verified by Microsoft), look up that client's projects in your project tool, reply { "data": { "name": …, "notice": …, "projects": [ … ] } }.
  • portal-request workflow: create the ticket tagged with body.endUser.email, then reply { "message": "Thanks — we'll reply within a day.", "navigate": { "form": "portal-home" } } to land back on the overview.

Approval queue#

Managers see pending expense claims and approve or reject each with one click. The table redraws itself after every action.

Access: Verified with your own domain, or Protected with a Managers role.

form approvals (onload: list-pending webhook)
{ "fields": [
  { "id": "queue", "type": "table", "label": "Waiting for approval", "dataSource": "claims",
    "tableSearch": true, "pageSize": 25,
    "columns": [ { "field": "employee", "label": "Employee" }, { "field": "amount", "label": "Amount" },
                 { "field": "reason", "label": "Reason" }, { "field": "submitted", "label": "Submitted" } ],
    "rowActions": [
      { "id": "approve", "label": "Approve", "type": "webhook", "style": "primary",
        "webhookUrl": "https://n8n.example.com/webhook/claims/approve?id={{row.id}}" },
      { "id": "reject", "label": "Reject", "type": "webhook", "style": "danger", "confirmMessage": "Reject this claim?",
        "webhookUrl": "https://n8n.example.com/webhook/claims/reject?id={{row.id}}" }
    ] }
] }
  • list-pending: query claims with status pending; reply { "data": { "claims": [ … ] } }.
  • approve / reject: check the X-F2WF-User-Email header is a manager, update the claim by the id query value, notify the employee, reply { "message": "Approved" }. The table reloads its rows automatically.

Quote that ends at Stripe checkout#

A visitor picks options, sees the price, and pays — your workflow prices the order and creates the Stripe Checkout session, so prices can't be tampered with in the browser.

form quote (submit: create-checkout webhook)
{ "submitText": "Continue to payment", "fields": [
  { "id": "plan", "type": "radio", "name": "plan", "label": "Package", "options": ["Starter", "Growth", "Scale"], "required": true, "defaultValue": "{{params.plan}}" },
  { "id": "seats", "type": "number", "name": "seats", "label": "Seats", "defaultValue": "5", "required": true },
  { "id": "email", "type": "email", "name": "email", "label": "Billing email", "required": true },
  { "id": "terms", "type": "markdown", "markdown": "By continuing you agree to the [terms](https://example.com/terms). You can cancel any time." }
] }
  • create-checkout: look up the package price on the server, create a Stripe Checkout Session (n8n's Stripe node or an HTTP Request to /v1/checkout/sessions) with success_url pointing at a thank-you page, then reply { "redirectUrl": "<session.url>" }. The widget sends the visitor straight to Stripe.
  • stripe-webhook (a second workflow, called by Stripe): on checkout.session.completed, provision the order and email the receipt.

Link to it with a preselected package: https://your-site.com/buy?plan=Growth.

AI answer page#

A visitor pastes a contract (or a job description, a support question…) and gets a formatted AI answer on the next page. Sign-in keeps strangers from spending your model budget.

Access: Verified (any Microsoft account), or Public with a strict rate limit for a lead magnet that collects an email first.

form review (submit: run-review webhook)
{ "submitText": "Review it", "fields": [
  { "id": "text", "type": "textarea", "name": "contract", "label": "Paste the contract", "required": true },
  { "id": "focus", "type": "select", "name": "focus", "label": "Focus on", "options": ["Risks", "Payment terms", "Termination"] }
] }
form review-result (onload: get-review webhook)
{ "fields": [
  { "id": "answer", "type": "markdown", "dataSource": "review", "maxHeight": 600 },
  { "id": "again", "type": "link", "label": "Review another", "linkAction": "navigate", "linkTargetForm": "review" }
] }
  • run-review: send body.data.contract to your model (n8n's AI Agent or OpenAI/Anthropic node) asking for a markdown answer, store it with an id, reply { "navigate": { "form": "review-result", "params": { "id": "<id>" } } }.
  • get-review: load the stored answer by body.params.id (check it belongs to body.endUser.id on a Verified form) and reply { "data": { "review": "### Summary\n…" } }.

Model output is shown as markdown: headings, lists and tables render, while any HTML or script in the answer is shown as plain text.

Order status lookup#

Customers check an order without logging in: they enter the order number and the email it was placed with.

form track (submit: find-order webhook)
{ "submitText": "Find my order", "fields": [
  { "id": "order", "type": "text", "name": "order", "label": "Order number", "required": true, "defaultValue": "{{params.order}}" },
  { "id": "email", "type": "email", "name": "email", "label": "Email used for the order", "required": true }
] }
form track-result (onload: order-details webhook)
{ "fields": [
  { "id": "status", "type": "markdown", "dataSource": "summary" },
  { "id": "items", "type": "table", "label": "Items", "dataSource": "items",
    "columns": [ { "field": "name", "label": "Item" }, { "field": "qty", "label": "Qty" } ] }
] }
  • find-order: look the order up in Shopify/WooCommerce; if the email matches, store a short-lived lookup token and reply { "navigate": { "form": "track-result", "params": { "t": "<token>" } } }, otherwise { "message": "We couldn't find that order." , "refresh": true }.
  • order-details: resolve body.params.t to the order and reply with a markdown summary and the items.

Never pass the raw order number alone to the result page — anyone could guess the next one. Use a random token (as above) or make the result page Verified.

More ideas#

  • Bookkeeper intake: a Verified upload form per client; the onload webhook shows a "still missing" checklist as markdown task list (- [x] T4, - [ ] RRSP receipt).
  • Event check-in: a searchable attendee table with a Check in row action.
  • Tenant maintenance: Verified request form with photo upload, plus a table of open tickets for that tenant.
  • Ops console: buttons for "Re-run sync", "Resend invoice" that wrap workflows a teammate shouldn't touch directly.