Skip to main content

How to manage employee leave requests and approvals end to end in Formaloo

Learn how to build an employee leave request workflow in Formaloo, with manager-email routing, an AI-flagged coverage check, and automatic approval emails.

What you'll build

By the end of this guide, you'll have a single leave request form that routes itself to whichever manager an employee names, no fixed approval hierarchy required. Every request gets an AI-generated coverage check flagging schedule conflicts before anyone reviews it, and Status changes automatically trigger the right email to the employee. People Ops works from an internal Kanban pipeline with filtered views for what's pending, approved, rejected, and unpaid.

When to use this

  • Your company still runs leave requests over email, and approvals get buried in someone's inbox for days

  • You don't have a fixed reporting hierarchy in your HR system, so "route to the employee's manager" needs to work off whatever email the employee provides, not a predefined org chart

  • HR wants a private, internal read on whether a request overlaps with other approved leave before anyone signs off on it

  • You need one place to see approved leave by date range, without exporting spreadsheets every time someone asks

Part 1 — Build the leave request form

This is the only form in the workflow. Employees fill out the public section when they submit a request; Status, Assignee, and Internal notes are admin-only and live on the same record, so People Ops reviews everything from one place instead of a separate system.

1. Open Magic Create: From your Formaloo homepage, click Magic Create. Paste the prompt below, then click Create.

Create a single-page leave request form for employees. Public fields: full name (short text), work email address (email field), department (dropdown: Engineering, Sales, Marketing, Support, Finance, HR, Operations, Other), leave type (dropdown: Vacation, Sick leave, Personal, Bereavement, Parental leave, Unpaid leave), start date (date field), end date (date field), reason for leave (long text, required), reviewing manager's email address (email field). Also add a hidden statement field titled "Date warning" that reads "Your end date is before your start date. Please double-check before submitting." Add these admin-only fields: Status as a dropdown with options Submitted, Awaiting manager review, Approved, Rejected; an Assignee field titled Assignee; and Internal notes as a long text field.

2. Verify your fields: Your form should now look like the table below. Magic Create will have generated most of this structure automatically. Open each field's settings and check that the field ID matches exactly, since logic, emails, and the PDF template all reference these IDs.

Field (question form)

Field ID

Type

Section

What's your full name?

employee_name

Short text

Public

What's your work email address?

employee_email

Email

Public

Which department are you in?

department

Dropdown

Public

What type of leave are you requesting?

leave_type

Dropdown

Public

When does your leave start?

start_date

Date

Public

When does your leave end?

end_date

Date

Public

What's the reason for your leave request?

reason

Long text, required

Public

What's your manager's email address?

manager_email

Email

Public

Date warning

date_warning

Statement, hidden by default

Public

Status

status

Dropdown: Submitted / Awaiting manager review / Approved / Rejected

Admin only

Assignee

assignee

Assignee

Admin only

Internal notes

internal_notes

Long text

Admin only

📖 See what are admin-only fields and how they help for how Status, Assignee, and Internal notes behave differently from the fields above them.

3. Add the coverage check field: Click Add field and choose AI Analysis. It arrives admin-only by default. Give it the title "Coverage check" and field ID coverage_check, then open its prompt box and write: "Based on @department, @leave_type, @start_date, and @end_date, check whether this request overlaps with other already-approved leave in the same department. Flag any overlap or blackout-period conflict in one short paragraph, or state that there's no conflict." Use the @ menu to insert each field rather than typing field names from memory.

Note: The AI Analysis field is available on the Business and Enterprise plans. It runs automatically on every submission, there's no separate step to trigger it, and it always stays admin-only, so the employee never sees it.

💡 Want the full picture of how this field behaves, including why its output can arrive slightly after the rest of the submission? How to generate AI analysis on form submissions without showing it to respondents in Formaloo covers it in full.

4. Publish the form: Click Publish in the island bar at the top of the editor.

Part 2 — Create your email templates

Three templates fire automatically as the request moves through the workflow: a review request to the manager, an approval notice to the employee, and a rejection notice to the employee. Build all three now so they're ready to attach to logic in Part 4.

1. Open the email template editor: Click your profile icon → Apps & integrationsCustom email templatesAdd new template.

2. Build each of the three templates: Give each a name and subject line, then clear the body field, add an AI block, and paste the prompt below it. Save each one before moving to the next.

Manager review request (to the reviewing manager) Subject: New leave request from @employee_name needs your review AI prompt: "Write a clear, efficient email to a manager letting them know a team member has submitted a leave request that needs their review. Reference the employee's name (@employee_name), leave type (@leave_type), start date (@start_date), end date (@end_date), and reason (@reason) if one was given. Keep the tone neutral and businesslike, this is a routine internal notification, not a sales pitch. State plainly what's being asked: review the request and let HR know the decision. 3-4 sentences, under 80 words." Design: white background, single centered column, max-width 560px, Inter/system-ui font. Present the leave details as a compact key-value data table rather than inline prose. Muted footer in #999 with a placeholder for the company name.

Leave approved (to the employee) Subject: Your leave request has been approved AI prompt: "Write a warm, brief confirmation email to an employee whose leave request was approved. Reference their leave type (@leave_type), start date (@start_date), and end date (@end_date). Keep it upbeat but short, and add one line reminding them to hand off any pending work before they're out. Friendly, professional tone. 3-4 sentences, under 70 words." Design: same layout as above, with a small green "Approved" status badge near the top and the dates shown in the same compact data table.

Leave rejected (to the employee) Subject: An update on your leave request AI prompt: "Write a calm, respectful email telling an employee their leave request was not approved. Reference their leave type (@leave_type) and requested dates (@start_date, @end_date) without dwelling on them. Avoid harsh or bureaucratic language, and invite them to reach out to their manager or HR to discuss timing or alternatives. Tone: empathetic, non-defensive, never apologetic to the point of sounding uncertain. 3-4 sentences, under 70 words." Design: same layout, with a muted amber (not red) "Not approved" status badge, so the two decision emails feel like one consistent family.

📖 See how to create and send custom email templates for the full template editor walkthrough, including how AI can generate the HTML design from a prompt.

Part 3 — Create your PDF template

One PDF template captures the outcome once a decision is made: employee and manager details, the leave dates and reason, the AI-generated coverage check, and the final status. Logic generates it automatically in Part 4. You're just building it here.

1. Open the PDF template editor: Click your profile icon → Apps & integrationsCustom PDF templatesAdd new template.

2. Switch to HTML view and paste the template below: This uses answer piping to pull in field values, including @rowid for the reference number and @created_at for the submission date. It's laid out in three sections: Employee, Leave details, and Internal review, the last of which holds the Status badge, the reviewer, the coverage check, and internal notes, everything the employee's version of this data should never include.

Leave request decision record

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Leave Request Decision Record</title> <style>   * { box-sizing: border-box; }   body {     margin: 0;     padding: 0;     background: #ffffff;     font-family: 'Inter', system-ui, -apple-system, sans-serif;     color: #1a1a1a;   }   .page {     max-width: 760px;     margin: 0 auto;     padding: 60px 72px;   }    /* Header */   .header {     margin-bottom: 40px;   }   .header h1 {     font-size: 22px;     font-weight: 600;     margin: 0 0 12px 0;     color: #1a1a1a;   }   .header-meta {     display: flex;     gap: 32px;     font-size: 12px;     color: #999999;   }   .header-meta span strong {     color: #555555;     font-weight: 500;   }    /* Status badge */   .status-badge {     display: inline-block;     font-size: 11px;     font-weight: 600;     letter-spacing: 0.04em;     text-transform: uppercase;     padding: 4px 11px;     border-radius: 20px;     background: #f2f2f2;     color: #666666;   }    /* Sections */   .section {     margin-bottom: 32px;   }   .section-title {     font-size: 10px;     font-weight: 600;     text-transform: uppercase;     letter-spacing: 0.08em;     color: #aaaaaa;     margin-bottom: 14px;   }    /* Field grid */   .field-grid {     display: grid;     grid-template-columns: 1fr 1fr;     gap: 0 32px;   }   .field-full {     grid-column: 1 / -1;   }   .field {     padding: 10px 0;     border-bottom: 1px solid #ececec;   }   .field-label {     font-size: 11px;     color: #999999;     margin-bottom: 4px;   }   .field-value {     font-size: 14px;     color: #1a1a1a;     line-height: 1.5;   }    /* Internal note inset */   .internal-block {     background: #f9f9f9;     border-left: 3px solid #dcdcdc;     padding: 14px 18px;     font-size: 13px;     color: #555555;     line-height: 1.6;     border-radius: 0 4px 4px 0;   }    /* Footer */   .footer {     margin-top: 56px;     padding-top: 20px;     border-top: 1px solid #ececec;     display: flex;     justify-content: space-between;     font-size: 11px;     color: #999999;   } </style> </head> <body>   <div class="page">      <div class="header">       <h1>Leave Request Decision Record</h1>       <div class="header-meta">         <span><strong>Reference:</strong> LR-@rowid</span>         <span><strong>Submitted:</strong> @created_at</span>       </div>     </div>      <div class="section">       <div class="section-title">Employee</div>       <div class="field-grid">         <div class="field">           <div class="field-label">Full name</div>           <div class="field-value">@employee_name</div>         </div>         <div class="field">           <div class="field-label">Work email</div>           <div class="field-value">@employee_email</div>         </div>         <div class="field">           <div class="field-label">Department</div>           <div class="field-value">@department</div>         </div>         <div class="field">           <div class="field-label">Reviewing manager</div>           <div class="field-value">@manager_email</div>         </div>       </div>     </div>      <div class="section">       <div class="section-title">Leave details</div>       <div class="field-grid">         <div class="field">           <div class="field-label">Leave type</div>           <div class="field-value">@leave_type</div>         </div>         <div class="field">           <div class="field-label">Duration</div>           <div class="field-value">@start_date &nbsp;&rarr;&nbsp; @end_date</div>         </div>         <div class="field field-full">           <div class="field-label">Reason</div>           <div class="field-value">@reason</div>         </div>       </div>     </div>      <div class="section">       <div class="section-title">Internal review</div>       <div class="field-grid">         <div class="field">           <div class="field-label">Status</div>           <div class="field-value"><span class="status-badge">@status</span></div>         </div>         <div class="field">           <div class="field-label">Reviewed by</div>           <div class="field-value">@assignee</div>         </div>         <div class="field field-full">           <div class="field-label">Coverage check (AI-generated, internal use only)</div>           <div class="internal-block">@coverage_check</div>         </div>         <div class="field field-full" style="border-bottom: none; margin-top: 14px;">           <div class="field-label">Internal notes</div>           <div class="field-value">@internal_notes</div>         </div>       </div>     </div>      <div class="footer">       <span>Confidential — internal HR record, not for external distribution</span>       <span>@form_title</span>     </div>    </div> </body> </html>

Kept as HR's audit record for every decision: employee and manager details, leave type and dates, the reason, the coverage check, and the final status, all in one document.

📖 See how to create PDF templates to turn responses into documents for the full editor walkthrough.

Part 4 — Automate routing and approvals with advanced logic

This is where the workflow comes together. One set of rules assigns every new request to People Ops, emails the reviewing manager, warns the employee about mismatched dates, and, once a decision is made, emails the employee and generates the decision PDF. Magic Logic can build all of it from a single prompt.

1. Open Magic Logic: In the form editor, open Advanced logic from the form settings panel on the right side, then go to the Logic tab. Click Magic Logic in the top right corner.

💡 Want a rule to fire the moment a request is first submitted, versus one that reacts whenever the record changes later? What is On Submit logic and how it works and what is On Update logic and how it works cover the difference.

2. Describe the full workflow in one prompt: Paste the prompt below and click Generate rules.

When the form is submitted: assign the record to the People Ops team, set status to "Awaiting manager review," and send the "Manager review request" email to the manager email field. When end date is before start date, show the Date warning field, which is hidden by default. When status is changed to "Approved": send the "Leave approved" email to the employee email field, and generate the leave request decision PDF. When status is changed to "Rejected": send the "Leave rejected" email to the employee email field, and generate the leave request decision PDF.

3. Review and approve each rule: The AI previews every rule it built. Approve, redo, or cancel each one individually, then confirm the correct email template is selected for each "Send email" action and the correct PDF template for each "Generate PDF" action.

4. Save your logic: Click Save in the top right corner.

Note: The coverage check field generates after the response row is created, so if you also want it piped into an On Submit email, the value can come through blank. That's why the decision PDF, which does reference it, is generated On Update instead, once People Ops has already had time to review the request.

📖 See what is logic in Formaloo and how to add advanced logic to your form for more on how these rules work. For the full list of supported variables, see how to dynamically pull form data into custom emails, PDFs, and AI prompts.

Part 5 — Set up the People Ops pages

No client portal is needed here. Employees submit through the open form link, and the only people who ever need restricted access are your own People Ops team, working from pages inside the same project.

1. Create the People Ops team: In your workspace settings, go to Members, create a team called People Ops, and add whoever handles leave requests. This is the team the Assignee field routes to.

💡 Want to route work to a group instead of naming one person every time? What is a team in Formaloo and how to manage it covers setting teams up. And for the Assignee field itself: what is the Assignee field in Formaloo and how to use it.

2. Build the All requests page: Add a Kanban board grouped by Status, with columns for Awaiting manager review, Approved, and Rejected. Dragging a card between columns updates the record's Status and triggers the matching logic automatically.

📖 See how to create a Kanban board for the setup.

3. Build the filtered views: Add My assigned requests, a table filtered to Assignee = logged-in user, sorted newest first. Add Awaiting manager review, filtered to Status = Awaiting manager review, sorted oldest first. Add Approved leave, filtered to Status = Approved, grouped by month and sorted by start date. Add Rejected requests, filtered to Status = Rejected. Add Unpaid leave requests, filtered to Leave type = Unpaid leave, since it has payroll implications the other categories don't.

📖 See how to sort and filter your submissions data for the underlying filters used on these pages.

4. Build the department chart: Add a bar chart of approved leave grouped by department, for spotting coverage gaps before they become a problem.

5. Restrict the group to People Ops: On each page above, open the three-dot menu → Access, and restrict it to internal users on the People Ops team. Since Status, Assignee, and Internal notes are all admin-only, this keeps the entire review pipeline invisible to anyone outside that team.

📖 See how to restrict users' access to pages in your portal for the full walkthrough of internal team-based page access.

What you now have

You now have a leave request workflow that routes itself to whatever manager an employee names, with no fixed hierarchy to configure or maintain. Every request arrives with an AI-generated coverage check already flagging scheduling conflicts, and a single Status change fires the right email without anyone drafting it by hand. People Ops works from one internal pipeline instead of a scattered inbox, with a permanent decision record for every request.

Ready-to-use templates

Don't build this from scratch — we've already put it together for you.

Don't have a form yet? Create one in seconds with Magic Create — describe what you need and Formaloo builds the form for you.

What's next

Learn more how-tos

Did this answer your question?