What you'll build
By the end of this guide, you'll have a purchase request form that checks its own evidence for completeness, runs an AI read on vendor risk before anyone reviews it, and routes each request through the right approval chain based on how much it costs. Small purchases approve themselves instantly, mid-size purchases go to a department manager, and larger purchases get manager sign-off followed by finance review. Every approved request closes with a branded PDF purchase order and a role-specific view for requesters, managers, and finance.
When to use this
Your procurement inbox fills up with requests missing a vendor quote or the wrong cost center, and someone has to notice and chase it down manually
Every purchase, whether it's a $50 supply order or a $20,000 equipment purchase, currently goes through the same slow approval chain
Finance doesn't find out about a risky vendor or an inflated quote until after a manager has already signed off
You want department managers and finance to each see only the requests that are actually theirs to review, not the whole company's spending
Nobody outside procurement has a single, exportable record of who approved a purchase and why
💡 Want a request to move through review, approval, or rejection stages automatically? How to build an approval workflow in Formaloo is the foundational guide to approval workflows in general. This article builds a complete, spend-based version of that pattern.
Part 1 — Build the purchase request form
This is the form every request starts from. It captures the requester's details, the purchase itself, and the vendor evidence the rest of the workflow depends on, along with the admin-only fields that track status and ownership behind the scenes. The fastest way to build it is with Magic Create: describe the form and Formaloo generates the fields for you.
1. Create a new project: From your Formaloo homepage, start a new project with Form. It comes with one form already attached, which is the fastest starting point for this workflow.
2. Build the form with Magic Create: From your homepage, click Magic Create and paste a prompt describing the form: "Build a purchase request form for an internal procurement workflow. Include: full name, email address, department (dropdown), item or service being purchased (long text), vendor name, total purchase amount (number), cost center, justification for the purchase (long text), and a file upload for the vendor quote or invoice. Also add these admin-only fields: a Status dropdown with the options Missing info, Auto-approved, Pending manager approval, Pending finance approval, Approved, and Rejected; an Assignee field; and an Internal notes long text field." Click Create.
3. Verify your fields: Your form should look like this. Magic Create will have generated most of it, so verify each field and field ID matches exactly.
Field (question form) | Field ID | Type |
What's your full name? |
| Short text |
What's your email address? |
| Short text |
Which department are you requesting for? |
| Dropdown |
What item or service are you purchasing? |
| Long text |
Who's the vendor? |
| Short text |
What's the total purchase amount? |
| Number |
What cost center should this be charged to? |
| Short text |
Why do you need this purchase? |
| Long text |
Upload the vendor quote or invoice |
| File upload |
Status |
| Dropdown (admin-only) |
Assignee |
| Assignee (admin-only) |
Internal notes |
| Long text (admin-only) |
💡 Want internal fields, like status, assignee, or scores, invisible to the person filling out the form? What are admin-only fields and how they help is the mechanism behind all three admin-only fields above.
4. Publish the form: Click Publish in the island bar at the top of the editor to make it live.
Part 2 — Flag incomplete requests and notify the requester
Before anything routes to a manager, the workflow checks that the two pieces of evidence it actually needs, the vendor quote and the cost center, are there. If either is missing, the request gets flagged and the requester hears about it immediately instead of an approver discovering the gap later.
1. Create the missing-information email template: Click your profile icon → Apps & integrations → Email templates → + Add new template. Name it "Missing information" and use the @ menu to insert each field reference rather than typing it from memory. Here's the full template:
Subject: Your purchase request needs more information
Body: Hi @requester_name,
Thanks for submitting your purchase request for @item_description from @vendor_name (@amount). Before it can move forward, we need one more thing: either the vendor quote or invoice, or the cost center, is missing.
Please reply to this email or update your submission with the missing item, and we'll pick it back up right away.
Thanks, The Procurement Team
📖 See how to create and send custom email templates for the full template editor walkthrough.
2. Open Advanced logic: In the form editor, open the form settings panel on the right side and click Advanced logic, then go to the On submit tab.
💡 Want a rule to fire the moment a form is first submitted, like flagging a gap or sending a confirmation? What is On Submit logic and how it works is the foundational guide to this trigger.
3. Add the completeness rule with Magic Logic: Click Magic Logic in the top right corner of the Logic panel and paste: "If 'Upload the vendor quote or invoice' is not answered, or if 'What cost center should this be charged to?' is not answered, assign Status to Missing info, then send an email to the requester's email address using the Missing information template." Click Generate Rules.
4. Review and save: Approve the generated rule, make any manual adjustments, and click Save in the top right corner.
Part 3 — Add an AI read on vendor risk
This is the step that catches a suspicious quote or an outlier price before a human ever opens the request. An AI Analysis field reads the vendor quote and purchase details the moment the form is submitted and writes a private risk read that only approvers see. The requester never sees it, and there's no setting that changes that.
Note: The AI Analysis field is available on the Business and Enterprise plans.
1. Open the Add field panel: In your form editor, click Add field and select AI Analysis. It drops onto the canvas admin-only by default, with no position on the live form.
2. Write the prompt: Open the field's prompt box and write: "Based on @vendor_name, @item_description, @amount, and @vendor_quote, flag anything unusual about this purchase, such as an inflated price, a vendor that doesn't match the item, or missing pricing detail on the quote. Respond in one short paragraph." Use the @ menu to insert each field reference rather than typing it from memory.
💡 Want to pull a submitter's own answers into a prompt, email, or PDF? How to use answer piping in Formaloo covers the @field_id basics behind every piped reference in this workflow.
3. Set the field ID and title: Name the field "AI vendor risk summary" and set its field ID to ai_risk_summary so it can be piped into emails and the PDF later.
4. Publish the form: Click Publish to make the field live.
Note: AI Analysis runs right after the response row is created, not before, so it usually finishes within seconds but isn't guaranteed to be ready the instant an On Submit email fires. The manager and finance notification emails in the next part reference this field, so if you ever see it come through blank, it caught up a few seconds after the email sent.
Part 4 — Route requests to managers and finance by spend threshold
This is where the workflow decides who needs to look at a request at all. Purchases at or under $500 approve themselves. Everything above that goes to the requester's department manager, and anything over $5,000 escalates to finance after the manager signs off. Adjust the two thresholds to match your own approval policy.
1. Create your manager and finance teams: Go to Workspace members → Teams and create one team per department that needs its own approver (for example, "Marketing managers," "Sales managers," "Engineering managers"), plus a "Finance" team.
💡 Want to assign work to a group instead of naming one person every time? What is a team in Formaloo and how to manage it covers setting these up.
2. Create two more email templates: The same way as Part 2, add these two templates.
"Auto-approval confirmation"
Subject: Your purchase request has been approved
Body: Hi @requester_name,
Good news: your purchase request for @item_description from @vendor_name (@amount) has been automatically approved. It falls under our auto-approval threshold, so no manager review is needed.
You're clear to proceed with the purchase. A purchase order will follow shortly.
Thanks, The Procurement Team
"Manager approval needed"
Subject: Approval needed: purchase request from @requester_name
Body: Hi team,
A new purchase request from @requester_name in @department needs your review.
Item: @item_description Vendor: @vendor_name Amount: @amount Justification: @justification
AI flagged the following before you review: @ai_risk_summary
Please open the request to approve or reject it.
Thanks, Formaloo Procurement Workflow
3. Add the routing rules with Magic Logic: Back in Advanced logic → On submit → Magic Logic, paste: "If Status is not Missing info and 'What's the total purchase amount?' is 500 or less, assign Status to Auto-approved, then send an email to the requester using the Auto-approval confirmation template. If Status is not Missing info and the purchase amount is greater than 500, assign Status to Pending manager approval, assign Assignee to the manager team matching the department (for example, assign to Marketing managers if Department is Marketing, Sales managers if Department is Sales, and so on for each department you have), then send an email to the assigned manager team using the Manager approval needed template." Click Generate Rules.
💡 Want incoming submissions to land on the right person's desk automatically, and only theirs? What is the Assignee field in Formaloo and how to use it is the foundational reference for the Assign action used here.
4. Create the escalation and rejection templates: Add these two templates.
"Finance approval needed"
Subject: Finance sign-off needed: purchase request ($@amount)
Body: Hi Finance team,
This purchase request from @requester_name in @department has already been approved by the department manager and now needs your sign-off because it exceeds our standard threshold.
Item: @item_description Vendor: @vendor_name Amount: @amount Justification: @justification
AI flagged the following before you review: @ai_risk_summary
Please open the request to finalize the decision.
Thanks, Formaloo Procurement Workflow
"Purchase not approved"
Subject: Your purchase request was not approved
Body: Hi @requester_name,
Your purchase request for @item_description from @vendor_name was not approved this time. If you'd like more detail, reach out to your manager or the finance team directly.
Thanks, The Procurement Team
5. Add the escalation rules: Switch to the On update tab and click Magic Logic. Paste: "If Status is changed to Approved and the purchase amount is greater than 5000, assign Status to Pending finance approval, assign Assignee to Finance, then send an email to Finance using the Finance approval needed template. If Status is changed to Rejected, send an email to the requester using the Purchase not approved template." Click Generate Rules.
💡 Want a rule to fire whenever an existing record changes, like a status flipping to Approved? What is On Update logic and how it works is the trigger behind every rule in this step.
6. Review and save: Approve both sets of rules and click Save.
Part 5 — Generate the purchase order and close out approved requests
Once a request clears its final approval, whether that's a manager signing off on a mid-size purchase or finance signing off on a large one, it should produce a document and notify the requester. This part builds that PDF and wires up the two rules that finish the workflow.
1. Create the PDF template: Click your profile icon → Apps & integrations → PDF templates → + Add new template. Switch to the HTML view and paste the template below. Name it "Purchase order" and save.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Purchase Order</title> <style> @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Source+Serif+Pro:ital@1&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; background: #ffffff; color: #1a1a1a; -webkit-font-smoothing: antialiased; } .page { max-width: 760px; margin: 0 auto; padding: 60px 72px; } /* Header */ .header { display: flex; justify-content: space-between; align-items: flex-start; padding-bottom: 28px; border-bottom: 1px solid #ececec; margin-bottom: 36px; } .header h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; color: #1a1a1a; } .header .meta { text-align: right; font-size: 12px; color: #999; line-height: 1.6; } .header .meta strong { color: #444; font-weight: 500; } /* Status badge */ .status-badge { display: inline-block; margin-top: 8px; padding: 4px 12px; border-radius: 20px; font-size: 11px; font-weight: 600; letter-spacing: 0.02em; background: #e8f5ec; color: #1a7f4e; } /* Sections */ .section { margin-bottom: 32px; } .section-title { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: #aaa; margin-bottom: 14px; } .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 32px; } .field { padding: 10px 0; border-bottom: 1px solid #f0f0f0; } .field.full { grid-column: 1 / -1; } .field .label { font-size: 11px; color: #999; margin-bottom: 3px; } .field .value { font-size: 14px; color: #1a1a1a; font-weight: 500; } .field .value.muted { font-weight: 400; color: #444; } /* Highlight callout for the amount */ .highlight { background: #f6f8fb; border-radius: 8px; padding: 20px 24px; display: flex; justify-content: space-around; align-items: center; margin-top: 8px; } .highlight .item { text-align: center; } .highlight .item .label { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: #98a2b3; margin-bottom: 6px; } .highlight .item .value { font-size: 22px; font-weight: 700; color: #1a1a1a; } /* Inset block for AI risk read + internal notes */ .inset { background: #f9f9f9; border-left: 3px solid #d8d8d8; padding: 16px 20px; border-radius: 0 4px 4px 0; font-size: 13px; color: #555; line-height: 1.6; } .inset-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: #b0b0b0; margin-bottom: 8px; } /* Signature */ .signature-block { margin-top: 24px; padding-top: 20px; border-top: 1px solid #f0f0f0; } .signature-name { font-family: 'Source Serif Pro', Georgia, serif; font-style: italic; font-size: 20px; color: #1a1a1a; border-bottom: 1px solid #d8d8d8; padding-bottom: 10px; margin-bottom: 8px; display: inline-block; } .signature-caption { font-size: 11px; color: #999; } /* Footer */ .footer { display: flex; justify-content: space-between; align-items: flex-end; padding-top: 20px; margin-top: 48px; border-top: 1px solid #eaeaea; font-size: 10px; color: #bbb; } .footer .org { font-weight: 500; color: #b0b0b0; } @media print { .page { padding: 40px 48px; } } </style> </head> <body> <div class="page"> <div class="header"> <div> <h1>Purchase Order</h1> <div class="status-badge">@status</div> </div> <div class="meta"> Reference No. <strong>PO-@rowid</strong><br> Submitted <strong>@created_at</strong> </div> </div> <div class="section"> <div class="section-title">Requester</div> <div class="grid"> <div class="field"> <div class="label">Full name</div> <div class="value">@requester_name</div> </div> <div class="field"> <div class="label">Email</div> <div class="value muted">@requester_email</div> </div> <div class="field"> <div class="label">Department</div> <div class="value muted">@department</div> </div> <div class="field"> <div class="label">Cost center</div> <div class="value muted">@cost_center</div> </div> </div> </div> <div class="section"> <div class="section-title">Purchase details</div> <div class="grid"> <div class="field"> <div class="label">Vendor</div> <div class="value">@vendor_name</div> </div> <div class="field"> <div class="label">Vendor quote / invoice</div> <div class="value muted">@vendor_quote</div> </div> <div class="field full"> <div class="label">Item or service</div> <div class="value muted">@item_description</div> </div> <div class="field full"> <div class="label">Justification</div> <div class="value muted">@justification</div> </div> </div> <div class="highlight"> <div class="item"> <div class="label">Purchase amount</div> <div class="value">$@amount</div> </div> </div> </div> <div class="section"> <div class="section-title">AI risk read</div> <div class="inset"> <div class="inset-label">Generated before review, for approver reference only</div> @ai_risk_summary </div> </div> <div class="section"> <div class="section-title">Decision record</div> <div class="grid"> <div class="field"> <div class="label">Final status</div> <div class="value">@status</div> </div> <div class="field"> <div class="label">Reviewed by</div> <div class="value muted">@assignee</div> </div> <div class="field full"> <div class="label">Internal notes</div> <div class="inset">@internal_notes</div> </div> </div> <div class="signature-block"> <div class="signature-name">@assignee</div> <div class="signature-caption">Final approver</div> </div> </div> <div class="footer"> <div>Confidential, internal purchasing record</div> <div class="org">Your organization name</div> </div> </div> </body> </html>💡 Want every form submission to generate a polished, branded document automatically? How to create PDF templates to turn responses into documents is the foundational guide to this.
2. Create the final approval email: Add this template.
"Purchase approved"
Subject: Your purchase request has been approved
Body: Hi @requester_name,
Your purchase request for @item_description from @vendor_name (@amount) has been fully approved. The purchase order is attached as a PDF for your records.
You're clear to proceed with the purchase.
Thanks, The Procurement Team
3. Add the closing rules: Back in Advanced logic → On update → Magic Logic, paste: "If Status is changed to Approved and the purchase amount is 500 or less, send an email to the requester using the Purchase approved template, then generate a PDF using the Purchase order template. If Status is changed to Approved and Assignee is Finance, send an email to the requester using the Purchase approved template, then generate a PDF using the Purchase order template." Click Generate Rules.
📖 See how to send custom PDFs with email notifications if you'd rather attach the generated PDF directly to the approval email instead of leaving it on the response row.
4. Review and save: Approve the rules and click Save. Every path through the workflow, whether auto-approved, manager-approved, or finance-approved, now ends with a document and a notification.
Part 6 — Give managers, finance, and requesters their own view
Department managers and the finance team are internal workspace members, not portal sign-ups, so their pages are restricted through internal access controls rather than a portal role. Requesters are the one group that actually needs to log into a portal, since they're checking on their own submissions from outside the workspace.
1. Add your data blocks: On your project's pages, add a Kanban board grouped by Status for full visibility, and Table blocks filtered to each manager team's assigned requests and to the finance team's pending queue.
2. Restrict manager and finance pages to their own team: Switch to Edit mode, open a page's three-dot menu → Access, and set it to Specific teams, selecting the matching manager or finance team.
💡 Want a whole page in your portal visible only to a specific role, not just specific data within a page? How to restrict users' access to pages in your portal covers this exact setting.
3. Activate the portal for requesters: Click the gear icon on your project → Activate client portal → Manage users → Setup wizard, and connect a new user directory so requesters can sign up and log in.
💡 Want to give clients, applicants, or teammates their own space to submit and track requests? How to create a portal and manage users' access is the foundational guide to this.
4. Restrict "My requests" to each requester's own data: On the requester-facing table, open Options → Manage access, select the requester's profile field, and turn on Allow users to view only their data.
💡 Want each logged-in user to see only their own submissions, not everyone else's? How to let users view and edit their own data in your portal is the mechanism behind this restriction.
Tip: If you're publishing this portal outside your workspace, you can set a custom domain instead of the default Formaloo URL, available on the Business plan or via the Brand removal add-on.
What you now have
You now have a purchase requisition workflow that catches its own missing evidence, flags vendor risk before a human opens the request, and routes every purchase through the right approval chain based on how much it costs. Small purchases clear themselves instantly, larger ones get exactly the sign-offs they need, and every decision closes with a branded PDF and a notification. Managers and finance each see only their own queue, and requesters can track their own requests without emailing anyone to ask where things stand.
What's next
Keep the request table manageable as volume grows Once you're processing more than a handful of requests a week, filtering by status, department, or amount keeps the table useful instead of overwhelming. → How to sort and filter your submissions data
Clean up old purchase records once they're no longer needed Procurement records often carry a retention policy, so automate the cleanup instead of tracking expiry dates manually. → How to automatically anonymize records after form submission in Formaloo
Add more departments as your team grows Every new department just needs its own manager team and one more line in the routing logic. → What is a team in Formaloo and how to manage it
Ready-to-use templates
Don't build this from scratch — we've already put it together for you.
Employee request workflow — Routes internal requests by type and tracks approvals for HR and ops teams. Swap in the spend-based routing and AI risk read from this article to turn it into a full procurement approval chain.
Job applicant tracking workflow — Tracks records across staged approvals with reviewer assignments. The same staged-assignment pattern this article uses for manager-then-finance routing.
Scholarship & grant application with scoring and approval — Auto-calculates scores and sends approval or rejection emails. A close parallel to this workflow's threshold-based auto-approval and email routing.
Don't have a form yet? Create one in seconds with Magic Create.
Learn more how-tos
See a simpler two-stage approval pattern If your own approval chain doesn't need spend-based branching or an AI risk read, this covers the same manager-then-final-approver pattern in its simplest form. → How to build a dual-approval request workflow
See AI scoring drive routing decisions in a different context This article uses the same AI-then-route pattern this workflow relies on, applied to inbound leads instead of purchase requests. → How to build an AI-powered lead qualification system
See AI reviewing a submission before a human does, in a hiring context Another workflow where AI reads a submission and produces a private summary before your team looks at it, useful for comparing prompt style. → How to build an AI-powered job application pipeline with candidate screening


