What you'll build
A public application form where short-term rental hosts submit property details, safety documentation, and complaint history. An AI field reads every submission the moment it lands and privately flags compliance risk before a reviewer opens the file. Logic routes high-risk and incomplete applications back for more information, sends the right email at every stage, and generates an official permit PDF the moment a permit is approved. Hosts track their status and renewal date from their own portal page, while your Code Compliance team works from a Kanban pipeline, an assigned-to-me queue, and a set of filtered views built around the workflow's real edge cases.
When to use this
Your city processes short-term rental permit applications by hand, and reviewers re-check documentation and complaint history on every single one before they can even start the review
You want every application flagged for risk the moment it arrives, so obviously incomplete or previously flagged properties don't sit in the same queue as clean, low-risk ones
Hosts have no way to check their own permit status, renewal date, or what's missing without calling or emailing your office
Permits need a renewal cycle, and nothing currently reminds a host before their inspection or renewal date arrives
Inspectors and compliance officers need their own queue of assigned properties instead of one shared, unsorted table
Part 1 — Build the host application form with Magic Create
This is the form every host fills out to apply for a permit. It captures property details, the four required documents, and complaint history, all in one submission, so nothing arrives split across emails and attachments.
1. Open Magic Create: From your Formaloo homepage, click Magic Create. Describe the form in plain text, or upload your existing paper permit application and let Magic Create convert it into an online form.
2. Write the Magic Create prompt: Describe every field you need, including which ones should be admin-only. For example: "Build a short-term rental permit application with the property address, the host's full name, email, and phone number, the rental type (entire home, private room, or shared room), maximum occupancy, a yes/no question asking about prior code violations or complaints with a text field to describe them if yes, four file uploads for proof of ownership or lease authorization, a fire safety inspection certificate, a floor plan showing exits and sleeping areas, and proof of liability insurance, and a yes/no consent question asking whether the host agrees to allow a compliance inspection if requested. Add these as admin-only fields: a permit status dropdown (Submitted, Under review, Needs more info, Inspection scheduled, Approved, Rejected, Renewal due), an assignee field for the reviewer, an internal notes field, and an inspection date field."
3. Click Create: Magic Create generates the form and its fields in seconds.
Your form should look like this. Magic Create will have generated most of it. Verify each field and field ID matches exactly.
📖 Want to know exactly what the Assignee field can do? What is the Assignee field in Formaloo and how to use it is the atomic reference.
Field (question form) | Field ID | Type |
What's the property address for this permit application? | property_address | Short text |
What's the property owner or host's full name? | host_name | Short text |
What's the best email to reach you at? | host_email | |
What's the best phone number to reach you at? | host_phone | Short text |
What type of short-term rental is this? | rental_type | Dropdown |
What's the maximum occupancy you're requesting for this permit? | max_occupancy | Number |
Has this property had any prior code violations or neighbor complaints? | prior_complaints | Yes/No |
Briefly describe the prior violation or complaint | prior_complaint_details | Long text |
Upload proof of property ownership or lease authorization | ownership_proof_upload | File |
Upload your current fire safety inspection certificate | fire_safety_cert_upload | File |
Upload a floor plan showing exits and sleeping areas | floor_plan_upload | File |
Upload proof of active liability insurance | insurance_upload | File |
Do you agree to allow a compliance inspection if one is requested? | inspection_consent | Yes/No |
Compliance inspection required notice | inspection_warning_notice | Meta (static content) |
Permit status | permit_status | Dropdown (admin-only) |
Assignee | permit_assignee | Assignee (admin-only) |
Internal notes | internal_notes | Long text (admin-only) |
Inspection date | inspection_date | Date (admin-only) |
The four document uploads are left as optional at the field level on purpose. That's what lets an incomplete submission still come through, so the logic in Part 3 can catch it and route it back to the host, instead of the form silently blocking submission.
📖 Want internal fields, status, assignee, notes, invisible to the person filling out the form? What are admin-only fields and how they help is the foundational guide to that mechanism.
Part 2 — Add the AI field that flags compliance risk
This is the part that does your reviewers' first pass for them. An AI Analysis field reads the four uploaded documents plus the complaint history the moment a permit is submitted, and writes a private risk read that only your team ever sees. The applicant never sees it, and there's no setting that changes that.
1. Add an AI Analysis field: In your form editor, add a field and select AI Analysis. It's admin-only by default and hidden from respondents automatically.
2. Write the prompt: Open the field's prompt box and use the @ menu to pipe in the relevant fields, including the four uploads directly. For example: "Read @ownership_proof_upload, @fire_safety_cert_upload, @floor_plan_upload, and @insurance_upload, along with @prior_complaints and @prior_complaint_details. Assess this short-term rental permit application's compliance risk as High, Medium, or Low, and explain your reasoning in one short paragraph, noting any missing documents or prior complaint history."
3. Name the field clearly: Title it "Compliance risk flag." This becomes the column header in your Responses table.
Once a host submits, Formaloo creates the response row and runs the AI Analysis field automatically, reading the uploaded files directly rather than just their filenames. While it generates, the cell shows a loading state, then displays the risk level and reasoning as plain text you can sort, filter, and export like any other field.
Note: the AI Analysis field is available on the Business and Enterprise plans only.
📖 See the full mechanics, including how it reads uploaded files, in how to generate AI analysis and let it update your form's own records.
Part 3 — Route permits with Magic Logic
Now that every submission arrives with a compliance risk read attached, use logic to reveal the right follow-up fields, flag high-risk and incomplete applications, and fire the right email at every stage, including a reminder before renewal.
1. Open Advanced logic: In the form's settings panel on the right side, open Advanced logic and go to the Logic tab.
2. Click Magic Logic: In the top right corner of the Logic panel, click Magic Logic.
3. Describe your visibility rules: Paste a prompt like: "Hide 'Briefly describe the prior violation or complaint' by default, and show it only when 'Has this property had any prior code violations or neighbor complaints?' is Yes, and require it in that case. Hide 'Compliance inspection required notice' by default, and show it only when 'Do you agree to allow a compliance inspection if one is requested?' is No."
4. Describe your submission and routing rules: In the same prompt, add: "On submit, set Permit status to Submitted, then run the compliance risk AI field. If Compliance risk flag is High, set Permit status to Needs more info and send an internal notification email to the assigned reviewer. If any of the four document uploads is empty, set Permit status to Needs more info and send the missing-documents email to the host. When Permit status changes to Approved, send the approval email to the host with the permit PDF attached. When Permit status changes to Rejected, send the rejection email to the host."
5. Describe the renewal reminder: Add: "Thirty days before the date in Inspection date, set Permit status to Renewal due and send the renewal reminder email to the host." Magic Logic can generate this kind of scheduled follow-up directly from a plain-language wait period, tied to the date field rather than a fixed calendar date.
6. Click Generate Rules: Review the AI-generated rules, approve, redo, or cancel each one.
7. Save your logic: Once you're satisfied, click Save in the top right corner.
📖 First time opening this panel? How to add advanced logic to your form walks through it in more detail.
Part 4 — Build the email templates
Hosts need to hear from you at every stage, when their application lands, when something's missing, when a decision is made, and before their permit needs renewing, without your team writing each one by hand.
1. Open the template library: Click your profile icon, go to Apps and Integrations, and open Custom Email Templates.
2. Create the submission confirmation: Click Add New Template, name it "Permit application received," and write a short confirmation using answer piping to pull in @host_name and @property_address.
3. Create the missing-documents notice: Add a second template, "Additional documentation needed," explaining plainly which document types are still required and linking back to the host's portal page.
4. Create the internal high-risk alert: Add a third template addressed to your reviewer, referencing @property_address and @host_name, letting them know a submission needs a closer look before deciding next steps.
5. Create the approval notice: Add a fourth template, "Permit approved," referencing @property_address, and note in the template that the generated PDF (built in Part 5) will be attached automatically.
6. Create the rejection notice: Add a fifth template, "Permit application update," referencing @property_address and, where useful, @internal_notes for the reviewer's reasoning.
7. Create the renewal reminder: Add a sixth template, "Permit renewal reminder," referencing @property_address and linking hosts back to their portal to start the renewal process.
📖 For a full walkthrough on writing and saving templates, see how to create and send custom email templates.
Part 5 — Build the PDF permit template
Once a permit is approved, hosts need an actual document, the official permit with their reference number, property details, and renewal date, not just an email saying so.
1. Open the PDF template library: Click your profile icon, go to Apps and Integrations, and open Custom PDF Template.
2. Add a new template: Click Add New Template, name it "Short-term rental permit," and switch the editor to the HTML view.
3. Paste the HTML below: This is the exact template used for this workflow. Property and host information sit in a two-column grid, current status and the renewal date are called out clearly, and a compliance acknowledgement sits in a soft inset block referencing the inspection consent the host agreed to. For the reference number, @rowid is piped directly into the header text as STR-@rowid, there's no separate form field for it.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Short-term rental permit</title> <style> @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #ffffff; color: #1a1a1a; } .page { max-width: 760px; margin: 0 auto; padding: 60px 72px; } .header { display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 1px solid #eeeeee; padding-bottom: 24px; margin-bottom: 36px; } .header-title { font-size: 24px; font-weight: 700; color: #1a1a1a; } .header-sub { margin-top: 6px; font-size: 13px; color: #999999; } .header-meta { text-align: right; font-size: 13px; color: #999999; } .header-meta .ref { font-size: 15px; font-weight: 600; color: #1a1a1a; margin-bottom: 4px; } .section { margin-bottom: 32px; } .section-title { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 1.5px; color: #aaaaaa; margin-bottom: 14px; } .field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 32px; } .field { padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid #f0f0f0; } .field.full { grid-column: 1 / -1; } .field-label { font-size: 11px; color: #999999; margin-bottom: 4px; } .field-value { font-size: 14px; color: #1a1a1a; font-weight: 500; } .status-badge { display: inline-block; padding: 4px 12px; border-radius: 999px; font-size: 12px; font-weight: 600; background: #eef6ee; color: #2e7d32; } .inset { background: #f9f9f9; border-left: 3px solid #dddddd; padding: 18px 20px; font-size: 13px; line-height: 1.6; color: #555555; border-radius: 0 6px 6px 0; } .footer { margin-top: 48px; padding-top: 20px; border-top: 1px solid #eeeeee; display: flex; justify-content: space-between; font-size: 11px; color: #999999; } </style> </head> <body> <div class="page"> <div class="header"> <div> <div class="header-title">Short-term rental permit</div> <div class="header-sub">City code compliance office</div> </div> <div class="header-meta"> <div class="ref">STR-@rowid</div> <div>Submitted @created_at</div> </div> </div> <div class="section"> <div class="section-title">Property information</div> <div class="field-grid"> <div class="field full"> <div class="field-label">Property address</div> <div class="field-value">@property_address</div> </div> <div class="field"> <div class="field-label">Rental type</div> <div class="field-value">@rental_type</div> </div> <div class="field"> <div class="field-label">Maximum occupancy</div> <div class="field-value">@max_occupancy</div> </div> </div> </div> <div class="section"> <div class="section-title">Host information</div> <div class="field-grid"> <div class="field"> <div class="field-label">Host name</div> <div class="field-value">@host_name</div> </div> <div class="field"> <div class="field-label">Email</div> <div class="field-value">@host_email</div> </div> <div class="field"> <div class="field-label">Phone</div> <div class="field-value">@host_phone</div> </div> </div> </div> <div class="section"> <div class="section-title">Permit status</div> <div class="field-grid"> <div class="field"> <div class="field-label">Current status</div> <div class="field-value"><span class="status-badge">@permit_status</span></div> </div> <div class="field"> <div class="field-label">Next inspection / renewal due</div> <div class="field-value">@inspection_date</div> </div> </div> </div> <div class="section"> <div class="section-title">Compliance acknowledgement</div> <div class="inset"> The host has agreed to allow a compliance inspection if one is requested by the code compliance office. This permit certifies status as of the submission date above and is subject to review, suspension, or revocation if the property is found in violation of local short-term rental regulations, occupancy limits, or safety requirements. </div> </div> <div class="footer"> <div>Confidential, for permit holder and city records only</div> <div>[City / department name]</div> </div> </div> </body> </html>4. Save your template: Give it a clear name and click Save.
The internal-only fields, Compliance risk flag, Internal notes, and Assignee, are deliberately left out of this document. Only the host-facing status and dates appear, since this PDF goes straight into the host's inbox.
📖 See how to create PDF templates to turn responses into documents and how to send custom PDFs with email notifications for the full setup on generating and attaching this PDF.
Part 6 — Set up the host portal and internal review pages
Hosts need somewhere to check status and renewal dates without calling your office, your Code Compliance team needs a pipeline and their own assigned queue, and city leadership needs a read on volume and risk without opening individual records.
1. Activate the portal: From your project, click the Settings icon and select Activate Portal. Open Manage User and run the Setup Wizard to connect a user directory, this is what lets hosts sign up and log in without needing a Formaloo account.
2. Add a Host role: In the User Directory, open Edit Profile Fields, scroll to User Roles, and add a "Host" role.
3. Build the host pages: Add "Apply for a permit" as the application form page, "My permit status" as a table filtered to the host's own records, and "Renewal due" as a table filtered to Permit status = Renewal due, also scoped to the host's own records. For both tables, switch to Edit Mode on the data block, click Options, scroll to Manage Access, select the profile field matching the host's email, and toggle on Allow users to view only their data.
4. Restrict the host pages to the Host role: On each page, click the three-dot menu next to the page name, select Access, and set external user access to the Host role you created.
5. Set up your Code Compliance team internally: Your reviewers and inspectors are internal users, not portal roles. Make sure they're workspace members, grouped into a team, for example "Code Compliance."
6. Build the "All applications" page: Add a Kanban board grouped by Permit status. Restrict it to your Code Compliance team via the page's Access menu → Internal users → Specific teams.
7. Build "My assigned permits": Switch to Edit Mode on that page's data block, click Options, scroll to Manage Access, select the Assignee field, and toggle on Allow assignees to view only their data.
8. Build the remaining filtered internal views: Add "High risk queue" filtered to Compliance risk flag = High, "Needs more info" filtered to Permit status = Needs more info and sorted oldest first, "Inspections scheduled" filtered to Permit status = Inspection scheduled and sorted by Inspection date, and "Renewals due soon" filtered to Permit status = Renewal due and sorted the same way. Restrict all four to the Code Compliance team the same way as step 6.
9. Build the Leadership reports group: Add "Permits by status," a bar chart grouped by Permit status, and "Risk distribution," a bar chart grouped by Compliance risk flag. Restrict both to internal leadership users, with full visibility across all properties.
Project pages spec
Group | Page | Access level | Data block | Filter | Sort | Form? |
Host | Apply for a permit | External users, Host role | Form | None | N/A | Yes |
Host | My permit status | Host, view own records only | Table | None (scoped by view-own-data) | Newest first | No |
Host | Renewal due | Host, view own records only | Table | Permit status = Renewal due | Newest first | No |
Code compliance | All applications | Internal users, Code Compliance team | Kanban | None | Grouped by Permit status | No |
Code compliance | My assigned permits | Internal, assignee = logged-in user | Kanban | Assignee = logged-in user | Newest first | No |
Code compliance | High risk queue | Internal, Code Compliance team | Table | Compliance risk flag = High | Newest first | No |
Code compliance | Needs more info | Internal, Code Compliance team | Table | Permit status = Needs more info | Oldest first | No |
Code compliance | Inspections scheduled | Internal, Code Compliance team | Table | Permit status = Inspection scheduled | Inspection date, soonest first | No |
Code compliance | Renewals due soon | Internal, Code Compliance team | Table | Permit status = Renewal due | Inspection date, soonest first | No |
Leadership reports | Permits by status | Internal leadership, full visibility | Chart (bar) | None | Grouped by Permit status | No |
Leadership reports | Risk distribution | Internal leadership, full visibility | Chart (bar) | None | Grouped by Compliance risk flag | No |
📖 First time building a portal? How to create a portal and manage users' access covers the full setup.
What you now have
A public application form that captures every document a permit review needs upfront, with an AI field quietly reading those documents and flagging compliance risk before a reviewer opens the file. High-risk applications and incomplete submissions route back automatically, so nothing sits unnoticed in a shared inbox. Hosts get a self-service portal for status and renewal, an actual PDF permit lands in their inbox the moment they're approved, and a reminder goes out on its own before the next renewal is due. Your Code Compliance team works from a pipeline, an assigned-to-me queue, and a handful of filtered views built around the workflow's real edge cases, while leadership gets a volume and risk read without opening a single record.
What's next
Give reviewers a second, dual sign-off step before approval If your jurisdiction requires two internal sign-offs before a permit is issued, say a compliance reviewer and a fire marshal, this shows the pattern for chaining two approval stages together. → How to build a dual-approval request workflow
See another AI-screened intake before a human looks This walks through a different workflow where AI reads a submission and screens it before your team does, useful context for refining your compliance risk prompt further. → How to build an AI-powered job application pipeline with candidate screening
Compare against another documentation-heavy intake pipeline This covers a similar pattern, conditional logic gating sensitive fields, a role-based portal, and an admin review pipeline, applied to healthcare intake instead of permits. → How to build a patient intake and consent workflow for healthcare clinics
Ready-to-use templates
Don't build this from scratch, we've already put it together for you.
Patient intake & consent workflow for healthcare — A two-page intake with conditional logic and an admin Kanban pipeline. Swap the clinical fields for permit documentation and reuse the same inspection-style pipeline.
Scholarship & grant application with scoring and approval — A multi-reviewer scoring workflow with automated approval and rejection emails. The same status-driven email routing applies directly to a permit decision.
AI lead qualification & scoring form — Scores incoming submissions with AI and routes them differently based on the score. Swap its scoring logic for the AI Analysis field pattern in Part 2 to keep the risk read fully internal.
Learn more how-tos
See a similar approval-to-document pattern in action Like this permit's approval-triggered PDF, this workflow turns an approved submission straight into an official document the requester receives automatically. → How to turn form responses into proposals and contracts
Compare against another capacity-and-document workflow This covers auto-generated PDFs and status tracking for a different public-facing intake, useful if your city also handles registrations alongside permits. → How to collect event registrations, manage capacity, and send automated confirmations
See another role-based review portal in practice Like the Code Compliance team's pipeline here, this shows a reviewer-facing portal with its own filtered queues sitting alongside a submitter-facing tracking page. → How to build a student submission and teacher review portal
