Time required. 45-60 minutes.
Prerequisites. A Google Workspace account with admin access, a running n8n instance, and a Google account that can create GCP projects.
This guide covers everything you need to set up the Employee Request Form workflow end to end.
The workflow lets employees submit any HR request (title change, pay change, equipment, schedule change, or other) through a single Google Form. The manager receives an approval email, and the decision is written back to the same Sheet row along with who decided and when.
Unlike the PTO workflow, this one does NOT touch Google Calendar or any directory service. It uses only Gmail and Google Sheets — two credentials in n8n.
Employee submits the form — The Google Form submission triggers an Apps Script on the linked Sheet. The script reads the new row by header name, looks up the row number, writes that row number back into a row_number column so the workflow can find this row later, and posts the form data (signed with HMAC) to the n8n form webhook.
n8n logs the request and notifies the manager — The workflow updates the same Sheet row to set Status = Pending, then sends the manager an HTML email with two buttons: Approve and Reject. The decision URL is derived from the form webhook URL by replacing /employee-request-form with /employee-request-decision and appending the row number plus all relevant fields as query parameters.
Manager clicks Approve or Reject — The decision webhook is a GET request (no body, no HMAC). It validates the action, reads the current row to confirm it has not already been actioned, then updates the row to set Status to Approved or Rejected, fills in the Decision timestamp and the Decided by (manager email), and emails the employee with the outcome.
Already-actioned protection — If the manager clicks an Approve or Reject link a second time, or the link is shared and clicked by someone else, the workflow reads the existing status and responds with a friendly "Already Processed" page instead of re-applying the decision.
Both paths (form submission and decision) are handled by a single workflow using two webhook triggers — the same pattern used by the PTO workflow.
The Google Form must have these six fields, in any order. The Apps Script matches them by header label, not position, so you can reorder the form fields freely:
| Form field | Sheet column header | Required? |
|---|---|---|
| Employee name | Employee name | Yes |
| Employee email | Employee email | Yes |
| Manager email | Manager email | Yes |
| Request type | Request type | Yes (short answer) |
| Details | Details | Yes |
| Effective date requested | Effective date requested | No (optional) |
The Request type field should be a short answer so employees can describe their request type freely. The Details field should be a long-form text field (paragraph) where employees can elaborate.
In addition to the Form Responses 1 tab, the Apps Script setup function also creates an Error Log tab with its own columns:
| Column | Type | Description |
|---|---|---|
| timestamp | date | ISO 8601, logged when an error occurs |
| error_type | string | validation_error, duplicate_error, or step_failure |
| employee_email | string | From the triggering record |
| employee_name | string | From the triggering record |
| node_name | string | Which node failed |
| error_message | string | Human-readable cause |
| resolved | string | Always "No" on insert; you can edit to "Yes" when resolved |
The Error Log tab stays empty during normal operation. It only gets populated when something fails (missing fields, API errors, etc.).
The workflow also writes these columns to the Form Responses 1 tab automatically. The Apps Script setup function adds them to the sheet and the workflow sets values on the existing row:
| Column | Set by | When |
|---|---|---|
| row_number | Apps Script | On form submit (used to match the row when a decision comes back) |
| Status | n8n | Pending on form submit, Approved/Rejected on decision |
| Decision timestamp | n8n | On decision (ISO 8601) |
| Decided by | n8n | On decision (manager email) |
Form Responses 1 tab with the 7 form columns. Do not add any extra columns to this tab yourself — the setup() function will add the n8n-managed columns after linking.This workflow uses only the Gmail API and the Google Sheets API. You do NOT need the Admin SDK, Calendar API, or a Service Account.
https://your-n8n.com/rest/oauth2-credential/callbackNote: You will only see the client secret once, so make sure to copy and/or download the JSON.
You only need two credentials for this workflow: Gmail OAuth2 and Google Sheets OAuth2. No Service Account, no Calendar, no Admin SDK.
Each credential you create in n8n has a unique ID. You need these IDs to configure your workflow.
You need two credential IDs:
Want to skip the manual setup?
Our templates include a configuration tool. Enter your details once and download a ready-to-import workflow. View templates →
https://tl-hr.com/configure/employee-request-form-google-workspace| Field | Description |
|---|---|
| Company name | Your company name |
| n8n webhook URL (base) | e.g. https://your-n8n-instance.com/webhook/employee-request-form — the form webhook path. The decision URL is derived automatically by replacing /employee-request-form with /employee-request-decision. |
| Google Sheets ID | The long string from your Sheet URL: https://docs.google.com/spreadsheets/d/THIS-ID/edit |
| Alert email | Email to receive notifications if any step fails |
| Gmail credential ID | The ID from the Gmail credential in n8n |
| Google Sheets credential ID | The ID from the Sheets credential in n8n |
Important: The Apps Script is installed on the Google Sheet (not the Form). The script uses a Sheet-based trigger that fires when a new form response row is added. This allows it to read the row number, write it back into the sheet, and pass it to the workflow so the workflow can update the correct row when the manager approves or rejects.
Code.gs file should be emptyemployee-request-form-google-workspace-appscript.gs file in a text editorCode.gs filesetup in the function dropdown and click the Run buttonThe setup function will:
row_number, Status, Decision timestamp, and Decided by columns to the Form Responses 1 tabError Log tab where the workflow writes any failuresonFormSubmit triggeremployee-request-form-google-workspace-configured.json fileImportant: Every node mutation in n8n via the API only saves a draft. After import, you MUST click Publish to make the workflow live. The production webhook URL hits the published (active) version. Without publishing, the webhook will keep returning 404.
Ready to automate?
The full Employee Request Form workflow includes the complete workflow, Apps Script, error handling, automatic retry, and the configuration tool. Setup takes 30-60 minutes if you follow this guide.
Status = Pendingrow_number column matches the actual row position in the sheetaction=approve and row=<the-row-number> in the URLaction=reject and row=<the-row-number> in the URLStatus = Approved with a Decision timestamp and Decided by set to the manager's emailStatus = Rejected with a Decision timestamp and Decided by set to the manager's email