Calendly + Google Sheets: clean HR access tracking
HR access changes sound simple until they aren’t. A “quick add” turns into three follow-ups, a missed seat removal, and a spreadsheet that nobody trusts. Calendly access automation fixes the messy middle.
HR managers feel it when approvals get buried in inboxes. Ops leads see it when licenses creep up. And the admin who “just handles Calendly” ends up owning the risk when someone shouldn’t still have access.
This workflow routes onboarding and offboarding requests through forms, logs everything in Google Sheets, and uses Gmail approvals before it touches Calendly. You’ll see how the flow works, what you need, and what to watch out for.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Calendly + Google Sheets: clean HR access tracking
flowchart LR
subgraph sg0["Offboarding form Flow"]
direction LR
n2@{ icon: "mdi:database", form: "rounded", label: "Get row(s) in sheet", pos: "b", h: 48 }
n3@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If1", pos: "b", h: 48 }
n4@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model1", pos: "b", h: 48 }
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/form.svg' width='40' height='40' /></div><br/>Offboarding form"]
n8@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set Calendy Organization id", pos: "b", h: 48 }
n11@{ icon: "mdi:robot", form: "rounded", label: "Email Agent Offboarding", pos: "b", h: 48 }
n13@{ icon: "mdi:message-outline", form: "rounded", label: "Email Man-in-the-loop Offboa..", pos: "b", h: 48 }
n15@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Approve offboarding?", pos: "b", h: 48 }
n17["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Get Calendly User"]
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Delete Calendly user"]
n21["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/form.svg' width='40' height='40' /></div><br/>End form page offboarding"]
n22@{ icon: "mdi:database", form: "rounded", label: "Offboarding complete", pos: "b", h: 48 }
n24["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/form.svg' width='40' height='40' /></div><br/>Form ending1"]
n3 --> n11
n6 --> n2
n17 --> n18
n4 -.-> n11
n2 --> n3
n15 --> n8
n15 --> n24
n18 --> n22
n22 --> n21
n11 --> n13
n8 --> n17
n13 --> n15
end
subgraph sg1["Onboarding form Flow"]
direction LR
n0@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model", pos: "b", h: 48 }
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Merge"]
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/form.svg' width='40' height='40' /></div><br/>Onboarding form"]
n7@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set Calendy Organization", pos: "b", h: 48 }
n9@{ icon: "mdi:database", form: "rounded", label: "New user", pos: "b", h: 48 }
n10@{ icon: "mdi:robot", form: "rounded", label: "Email Agent Onboarding", pos: "b", h: 48 }
n12@{ icon: "mdi:message-outline", form: "rounded", label: "Email Man-in-the-loop Onboar..", pos: "b", h: 48 }
n14@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Approve onboarding?", pos: "b", h: 48 }
n16["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Add user to Calendly"]
n19@{ icon: "mdi:database", form: "rounded", label: "Onboarding complete", pos: "b", h: 48 }
n20["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/form.svg' width='40' height='40' /></div><br/>End form page onboarding"]
n23["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/form.svg' width='40' height='40' /></div><br/>Form ending"]
n1 --> n10
n9 --> n1
n5 --> n9
n5 --> n7
n0 -.-> n10
n14 --> n16
n14 --> n23
n19 --> n20
n16 --> n19
n10 --> n12
n7 --> n1
n12 --> n14
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n6,n5 trigger
class n11,n10 ai
class n4,n0 aiModel
class n3,n15,n14 decision
class n2,n22,n9,n19 database
class n17,n18,n16 api
classDef customIcon fill:none,stroke:none
class n6,n17,n18,n21,n24,n1,n5,n16,n20,n23 customIcon
The Problem: Calendly access changes get missed (and untracked)
Onboarding and offboarding are full of tiny steps that don’t feel dangerous until you stack them up. Someone requests Calendly access, HR replies “approved,” an admin adds the seat later, and nobody records the final state. Offboarding is worse. A contractor leaves, the request comes in verbally, and the removal gets delayed because “I’ll do it after this meeting.” A week later you’re still paying for a seat and the access technically still exists. Honestly, the scariest part is not the work. It’s the lack of an audit trail when someone asks, “Who approved this?”
The friction compounds. Here’s where it breaks down in real teams.
- Requests arrive in different places (Slack, email, hallway chats), so tracking becomes guesswork.
- Manual Calendly updates are easy to postpone, which means offboarding drifts past the exit date.
- Approvals live in inbox threads, and digging them up during an audit is painfully slow.
- Without a single “source of truth” sheet, you can’t confidently answer who has access today.
The Solution: Approved requests in, Calendly seats updated, everything logged
This n8n workflow turns Calendly onboarding and offboarding into a controlled process you can trust. It starts with two simple intake forms: one for onboarding (name + email) and one for offboarding (email only). Every request gets written to Google Sheets so you have a durable record from the first second. Then OpenAI generates a clean, professional HTML email to HR with the request details, and Gmail sends it using a “send and wait” approval step so a human must explicitly approve before any access change happens. Once approved, n8n talks directly to Calendly’s API to invite a new user or remove an existing member. Finally, the workflow updates the same Google Sheet with the outcome (CALENDLY on/off) and shows the requester a clear completion screen.
Onboarding flows from form submission to a new row in Sheets, then to an HR approval email, and only then to a Calendly invite. Offboarding starts with a lookup in Sheets, verifies the person exists and currently has access, waits for HR approval, then removes the membership and logs the change.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you handle 10 access changes a week (new hires, role changes, offboarding). Manually, each one usually means about 10 minutes of back-and-forth plus another 10 minutes updating Calendly and “somewhere” tracking it, so you’re at roughly 3–4 hours weekly. With this workflow, the requester submits a form in about 2 minutes, HR taps approve in Gmail, and n8n handles the Calendly change and sheet update automatically. Your work becomes spot-checking instead of chasing.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets to store requests and access status.
- Gmail to send approvals and wait for responses.
- Calendly to invite and remove organization members.
- OpenAI API key (get it from your OpenAI dashboard).
- Calendly API token + org ID (get them from Calendly developer settings).
Skill level: Intermediate. You’ll connect accounts, paste API tokens, and map a few fields into your sheet.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A request comes in through a form. Onboarding collects first name, last name, and email. Offboarding only needs the email, which keeps it fast for managers and HR.
Google Sheets becomes the source of truth. Onboarding appends a new row right away. Offboarding searches the sheet first, so you only try to remove access when the person is actually listed as having it.
HR gets a clean approval email. OpenAI drafts a professional HTML message, then Gmail sends it using a wait-for-approval pattern. No approval, no change. Simple.
Calendly is updated through the API. Approved onboarding triggers an invite to your Calendly organization. Approved offboarding retrieves the membership and removes the user, then the sheet is updated to CALENDLY = on or off.
You can easily modify the approval routing to use a shared HR inbox or add a second approver for sensitive teams. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Form Triggers
Set up the two intake forms that initiate onboarding and offboarding.
- Open Onboarding Intake Form and set Form Title to
Calendly Onboardingand Form Description toCalendly Onboarding. - In Onboarding Intake Form, add fields for First Name, Last Name, and Email (email type), all required.
- Open Offboarding Intake Form and set Form Title to
Calendly Offboardingand Form Description toCalendly Offboarding. - In Offboarding Intake Form, add a required Email field.
- Confirm the parallel flow: Onboarding Intake Form outputs to both Append New Record and Assign Calendly Org in parallel.
Step 2: Connect Google Sheets for Onboarding and Offboarding Records
Configure the Google Sheets nodes that store onboarding data and find offboarding records.
- Open Append New Record and set Operation to
append. - Set Document to
[YOUR_ID]and Sheet togid=0(cached name:Foglio1). - Map columns in Append New Record: DATE to
{{ $now.format('dd/LL/yyyy') }}, EMAIL to{{ $json.Email }}, LAST NAME to{{ $json['Last Name'] }}, FIRST NAME to{{ $json['First Name'] }}. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Append New Record.
- Open Lookup Sheet Rows and set Document to
[YOUR_ID]and Sheet togid=0. - In Lookup Sheet Rows, set filters: EMAIL lookup value
{{ $json.Email }}and CALENDLY lookup valueon. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Lookup Sheet Rows, Mark Onboarding Complete, and Mark Offboarding Complete.
DATE, FIRST NAME, LAST NAME, EMAIL, and CALENDLY, or the append/update mappings will fail.Step 3: Set Up the AI Email Composition
Configure the AI agents that generate HR approval emails for onboarding and offboarding.
- Open Compose HR Onboarding Email and confirm Text is set to
=First name: {{ $('Onboarding Intake Form').item.json['First Name'] }} Laste name: {{ $('Onboarding Intake Form').item.json['Last Name'] }} Email: {{ $('Onboarding Intake Form').item.json.Email }}. - Ensure OpenAI Chat Engine is connected as the language model for Compose HR Onboarding Email and uses model
gpt-5.1. - Credential Required: Connect your openAiApi credentials in OpenAI Chat Engine (AI credentials are added to the parent node, not the agent).
- Open Compose HR Offboarding Email and confirm Text is set to
=First name: {{ $json['FIRST NAME'] }} Laste name: {{ $json['LAST NAME'] }} Email: {{ $json.EMAIL }}. - Ensure OpenAI Chat Engine B is connected as the language model for Compose HR Offboarding Email and uses model
gpt-5.1. - Credential Required: Connect your openAiApi credentials in OpenAI Chat Engine B.
Step 4: Configure HR Approval Emails and Conditional Checks
Send approval emails to HR and branch the workflow based on approval response.
- Open HR Approval Email Onboard and set Send To to
[YOUR_EMAIL], Operation tosendAndWait, and Message to{{ $json.output }}. - Set Subject in HR Approval Email Onboard to
Start Calendly Onboarding for user {{ $('Onboarding Intake Form').item.json['First Name'] }} {{ $('Onboarding Intake Form').item.json['Last Name'] }}?. - Under approval options, set Approval Type to
doubleand Limit Wait Time to45minutes. - Credential Required: Connect your gmailOAuth2 credentials in HR Approval Email Onboard and HR Approval Email Offboard.
- Open HR Approval Email Offboard and set Send To to
[YOUR_EMAIL], Message to{{ $json.output }}, and Subject toStart Calendly Offboarding for user {{ $('Row Exists Check').item.json['FIRST NAME'] }} {{ $('Row Exists Check').item.json['LAST NAME'] }}?. - Verify the logic nodes: Onboarding Approval Check evaluates
{{ $json.data.approved }}and routes to Create Calendly Invite on true, Show Onboard Rejected on false; Offboarding Approval Check routes to Assign Calendly Org ID on true, Show Offboard Rejected on false.
Step 5: Configure Calendly API Actions
Set the Calendly organization IDs and API requests used for onboarding invites and offboarding removals.
- Open Assign Calendly Org and set calendly_organization to
[YOUR_ID]. - Open Assign Calendly Org ID and set calendly_organization to
[YOUR_ID]. - In Create Calendly Invite, set URL to
=https://api.calendly.com/organizations/{{ $('Assign Calendly Org').item.json.calendly_organization }}/invitationsand Method toPOST. - In Create Calendly Invite, set body parameter email to
{{ $('Append New Record').item.json.EMAIL }}and header Authorization toBearer [CONFIGURE_YOUR_TOKEN]. - In Retrieve Calendly Member, set URL to
=https://api.calendly.com/organization_memberships?organization=https%3A%2F%2Fapi.calendly.com%2Forganizations%2F{{ $json.calendly_organization }}&email={{ $('Lookup Sheet Rows').item.json.EMAIL }}and header Authorization toBearer [CONFIGURE_YOUR_TOKEN]. - In Remove Calendly Member, set URL to
{{ $json.collection[0].uri }}, Method toDELETE, and header Authorization toBearer [CONFIGURE_YOUR_TOKEN].
[CONFIGURE_YOUR_TOKEN] with a valid Calendly token in all three HTTP nodes.Step 6: Configure Record Updates and Completion Screens
Finalize the workflow by updating the sheet status and displaying completion messages.
- Open Mark Onboarding Complete and set Operation to
updatewith matching column EMAIL. Map EMAIL to{{ $('Append New Record').item.json.EMAIL }}and CALENDLY toon. - Open Mark Offboarding Complete and set Operation to
updatewith matching column EMAIL. Map EMAIL to{{ $('Lookup Sheet Rows').item.json.EMAIL }}and CALENDLY tooff. - Confirm completion screens: Show Onboarding Completion has Completion Title
Onboarding completeand Completion MessageOnboarding complete. - Confirm offboarding completion screen: Show Offboarding Completion has Completion Title
Onboarding completeand Completion MessageOnboarding complete(adjust text if needed). - Review rejection screens: Show Onboard Rejected and Show Offboard Rejected show
Onboarding not approvedandOffboarding not approvedrespectively.
Step 7: Test and Activate Your Workflow
Run both paths to verify approvals, Calendly actions, and sheet updates.
- Click Execute Workflow and submit the Onboarding Intake Form with a test user.
- Approve the email from HR Approval Email Onboard and confirm that Create Calendly Invite runs and Mark Onboarding Complete updates the sheet.
- Submit the Offboarding Intake Form for a user with CALENDLY set to
onin the sheet, then approve via HR Approval Email Offboard. - Verify Retrieve Calendly Member and Remove Calendly Member execute, then check Mark Offboarding Complete updated CALENDLY to
off. - When results look correct, toggle the workflow to Active for production use.
Common Gotchas
- Google Sheets permissions can block updates even when the sheet “looks shared.” If rows stop appending, check the connected Google account and the spreadsheet sharing settings first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Calendly API tokens can expire or be scoped incorrectly. When HTTP requests fail, check the bearer token in the HTTP Request nodes and confirm the organization ID matches your Calendly org.
Frequently Asked Questions
About an hour if your tokens and sheet are ready.
No. You’ll mostly connect accounts and paste API credentials. The hardest part is usually mapping the right sheet columns.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API costs (often just a few cents per batch of emails) and whatever Calendly plan you already use.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and it’s a smart idea for larger teams. You can duplicate the Gmail “send and wait” approval used in HR Approval Email Onboard/Offboard and route it to IT after HR approves. Some teams also customize the OpenAI email agent to include role, department, and start/end dates. If you want different rules for contractors vs employees, the If checks can branch based on email domain or a “worker type” field in the form.
Usually it’s an invalid or expired bearer token in the HTTP Request nodes. Update the token, confirm your Calendly organization ID is correct in the Set nodes, and retry a single test request. If it fails only during busy periods, you may be hitting rate limits, so spacing requests slightly can help.
Hundreds per week is realistic for most teams.
Often, yes, because this isn’t just “send an email then update a row.” You’re doing lookups, conditional checks, waiting for human approval, and making authenticated API calls to Calendly. n8n handles branching logic cleanly, and self-hosting can be a big deal if you don’t want to pay more as volume grows. Zapier or Make can still work if you keep it very simple and don’t need the Sheets validation step. But once you care about audit trails and safe offboarding, you’ll appreciate the control here. Talk to an automation expert if you want a quick recommendation.
Once this is running, access changes stop being a “hope we remembered” task. You get cleaner records, safer offboarding, and a Calendly seat count you can actually trust.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.