Back to Employee Offboarding

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

Developer Handover Pack

Employee Offboarding Automation

[YourCompany.com] · HR Department · Prepared by FullSpec · [Today's Date]

This document is the complete technical reference for the Employee Offboarding automation. It covers the current-state process map, full agent specifications with IO contracts, the end-to-end data flow, and the recommended build stack. The FullSpec team owns all build, integration, and testing work described here. Your team's responsibility is to supply valid API credentials, confirm field mappings against live system data before testing begins, and sign off on each agent during the QA phase.

01Process snapshot

Step
Name
Description
1
Receive and Confirm Departure Notice
HR receives verbal or written notice and confirms the last working day informally via Slack or email. No central record is created at this stage. (20 min)
2
Update HR System with Exit Date
HR manually logs the departure date, reason, and employee status in BambooHR. Fields are sometimes left incomplete until the last day. (15 min)
3
Notify IT to Revoke System Access
HR sends an unstructured Slack message or email to IT to disable accounts. IT must interpret which systems are in scope. BOTTLENECK. (15 min)
4
IT Revokes Access Across Systems
IT manually works through Okta and Google Workspace to suspend accounts and transfer file ownership. Done inconsistently, often delayed. BOTTLENECK. (40 min)
5
Create Equipment Return Task
HR or the manager sends a message to the employee about returning hardware. No formal tracking system exists. (10 min)
6
Notify Payroll of Final Pay Details
HR emails payroll or the finance lead with the last working day, accrued leave, and deductions. Miscommunication here causes payroll errors. (20 min)
7
Conduct Exit Interview
HR schedules and runs the exit interview in person or via form. Notes are saved informally and rarely aggregated. (30 min)
8
Send Exit Survey Link
HR manually emails the departing employee a survey link after the interview. Frequently skipped when HR is busy. (10 min)
9
Confirm Task Completion and Close Record
HR follows up with IT, the manager, and payroll to confirm each task is done, then marks the record closed in BambooHR. Chase-and-confirm loop. BOTTLENECK. (30 min)
10
Log Offboarding Completion for Audit
HR creates a summary of all completed steps for compliance, usually in a shared spreadsheet or email thread. (20 min)
Time cost summary: Total manual time per offboarding cycle is 210 minutes (3.5 hours). At 2 to 4 offboardings per month this equals 420 to 840 minutes (7 to 14 hours) of manual work per month. At 3 runs per month the team spends approximately 3 hours per week on this process. The automation replaces steps 3, 4, 5, 6, 8, 9, and 10 entirely. Steps 1, 2, and 7 remain with the human team. Step 7 (exit interview) stays manual by design. Equipment return confirmation (a sub-task of step 5 and step 9) remains human-gated via a Jira task.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Access Revocation Agent

Handles all system access revocation the moment a departure is confirmed in BambooHR. Connects to Okta via the Users API to immediately suspend the employee's SSO session, revoking access to all downstream SaaS applications linked to Okta. Then calls the Google Workspace Admin SDK to disable the user account, set an automated out-of-office reply on the Gmail account, and transfer Google Drive ownership to the departing employee's line manager. All actions are logged to the automation platform's audit table. This agent produces a single structured confirmation payload that triggers the Task and Notification Agent. Complexity is Moderate because it spans two identity providers with different authentication models and requires a super-admin service account for Google Workspace.

Trigger
BambooHR webhook fires when an employee's status field changes to 'departing' or when a last_working_day date is set on the employee record.
Tools
BambooHR (inbound webhook), Okta (Users API), Google Workspace Admin SDK (Directory API)
Replaces steps
Step 3 (Notify IT to Revoke System Access), Step 4 (IT Revokes Access Across Systems)
Estimated build
10 hours / Moderate complexity
// Input (from BambooHR webhook payload)
employee_id: string          // BambooHR internal employee ID
full_name: string            // employee display name
email: string                // work email address (primary identifier)
last_working_day: date       // ISO 8601 date, e.g. 2025-04-30
manager_email: string        // line manager email for Drive transfer
department: string           // used to scope Jira project template
employment_type: string      // 'employee' | 'contractor'

// Output (confirmation payload passed to Task and Notification Agent)
okta_suspended: boolean      // true if Okta account suspension confirmed
okta_user_id: string         // Okta user UID for audit log
google_disabled: boolean     // true if Workspace account disabled
google_drive_transferred: boolean  // true if Drive ownership moved
auto_reply_set: boolean      // true if Gmail out-of-office reply activated
revocation_timestamp: datetime     // UTC timestamp of completed revocation
error_flags: string[]        // list of any step-level errors encountered
  • Okta API requires the token to have the okta.users.manage and okta.apps.manage scopes. Confirm the API token is generated from an Okta super-admin account, not a read-only service account. Standard Okta One App plan does not expose group management via API; confirm the org is on Okta Workforce Identity.
  • Google Workspace Admin SDK Directory API calls for account disable and Drive transfer require a service account with domain-wide delegation enabled and the scopes https://www.googleapis.com/auth/admin.directory.user and https://www.googleapis.com/auth/drive set in the Google Admin console. A super-admin must authorise the service account before build begins.
  • Dedupe behaviour: if the BambooHR webhook fires more than once for the same employee_id (duplicate webhook or retry), the agent must check Okta status before calling suspend. If already suspended, skip and log 'already_revoked' rather than returning an error.
  • Fallback: if the Okta API call fails after two retries, the agent must post a high-priority alert to the designated HR Slack channel with the employee name, error code, and a direct link to the Okta admin panel. The workflow must not silently fail.
  • Drive ownership transfer targets manager_email. If manager_email is null or the manager account is also inactive, transfer ownership to the HR Manager's Google account (configured as an environment variable HR_FALLBACK_EMAIL).
  • The auto-reply message copy must be confirmed with the HR team before build. Store the template text as an environment variable OFFBOARD_AUTO_REPLY_BODY so it can be updated without a code change.
  • Confirm before build: which BambooHR webhook event name is configured in the production instance ('Employee Status Changed' vs 'Custom Field Updated') and whether a webhook signing secret is enabled.
Task and Notification Agent

Triggered by the confirmed output of the Access Revocation Agent. Creates a structured Jira offboarding project board from a saved template, populating subtasks for equipment return, exit interview scheduling, and any outstanding manual items. Each subtask is assigned to the correct owner using department and manager data from the BambooHR payload. Sends a structured payroll notification to Xero via the Xero Accounting API, including the final working day and leave balance pulled from BambooHR. Dispatches the exit survey to the employee's personal email address via Google Workspace on the penultimate working day. Posts a completion summary to the HR Slack channel once all automated steps are confirmed. Closes the BambooHR record to 'offboarded' status after the Jira equipment return task is marked complete by the manager. Complexity is Moderate due to the number of tool integrations and the conditional logic around equipment return gating the final record closure.

Trigger
Access Revocation Agent publishes a confirmed output payload with okta_suspended: true and google_disabled: true. If either flag is false, this agent waits and re-polls every 5 minutes for up to 30 minutes before raising a Slack alert.
Tools
Jira (Projects API, Issues API), Xero (Accounting API, Payroll API), Google Workspace (Gmail API for exit survey), Slack (Incoming Webhooks or Web API), BambooHR (Employees API for record update)
Replaces steps
Step 5 (Create Equipment Return Task), Step 6 (Notify Payroll of Final Pay), Step 8 (Send Exit Survey Link), Step 9 (Confirm Task Completion and Close Record), Step 10 (Log Offboarding Completion for Audit)
Estimated build
10 hours / Moderate complexity
// Input (from Access Revocation Agent output payload)
employee_id: string
full_name: string
email: string                     // work email
personal_email: string            // for exit survey dispatch
last_working_day: date
manager_email: string
department: string
leave_balance_hours: number       // pulled from BambooHR Time Off API
okta_suspended: boolean
google_disabled: boolean
revocation_timestamp: datetime

// Output (per action, aggregated into Slack summary payload)
jira_board_url: string            // URL of the created Jira project
jira_equipment_task_id: string    // Jira issue key for equipment return subtask
xero_notification_sent: boolean   // true if payroll notification delivered
exit_survey_sent: boolean         // true if survey email dispatched
exit_survey_send_date: date       // penultimate working day date
slack_summary_posted: boolean
bamboohr_record_closed: boolean   // set after Jira equipment task completed
bamboohr_close_timestamp: datetime
error_flags: string[]

// On approval (equipment return gate)
// Manager marks jira_equipment_task_id as Done in Jira
// Jira webhook fires to the automation platform
// Agent calls BambooHR PATCH /v1/employees/{employee_id}
//   with status: 'offboarded' and offboard_date: today()
  • Jira board creation requires the Jira Software or Jira Work Management plan with API token authentication (Basic Auth with email and API token, or OAuth 2.0 three-legged for user-context actions). A Jira project template named 'HR-OFFBOARD-TEMPLATE' must exist in the target workspace before build. Confirm the template project key with the IT Admin.
  • Xero integration uses the Xero Accounting API. The payroll notification is a structured note or invoice memo, not a direct payroll run. Confirm whether the Xero org has Payroll (AU/NZ/UK) or Accounting-only enabled, as the available API endpoints differ. The finance lead must validate the leave_balance_hours field mapping against Xero's own records before the first live run.
  • Exit survey email must be sent to personal_email, not the work email which will have an auto-reply set. personal_email must be a confirmed field in BambooHR. If the field is empty, the step logs a warning and posts an alert to the HR Slack channel rather than failing the entire run.
  • Exit survey send timing: calculate penultimate_working_day as last_working_day minus one business day. The automation must exclude weekends and public holidays. Configure a public holiday calendar for the relevant jurisdiction as an environment variable JURISDICTION_HOLIDAY_CALENDAR before build.
  • Slack summary uses an Incoming Webhook URL stored as environment variable SLACK_HR_WEBHOOK. The summary message must list each completed task with a timestamp and flag any items still awaiting human action (equipment return, exit interview) with an amber indicator.
  • BambooHR record closure (PATCH status to 'offboarded') is gated on the Jira equipment return task reaching 'Done' status. The Jira webhook that fires this must be scoped to only the 'HR-OFFBOARD' project to avoid false triggers from other Jira activity.
  • Dedupe: if the Jira project for a given employee_id already exists (re-run scenario), the agent must skip project creation, log 'board_already_exists', and proceed to check task status rather than creating duplicate boards.
  • Confirm before build: personal_email field name in BambooHR API response, the exact Jira project template key, whether Xero is on Payroll or Accounting plan, and the Slack channel name for HR summaries.
Total estimated agent build time: Access Revocation Agent 10 hours + Task and Notification Agent 10 hours = 20 hours. Add 2 hours for end-to-end integration testing (see section 04). Grand total: 22 hours, matching the confirmed build effort in the project snapshot.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow with field names and API calls per step
// ================================================================
// EMPLOYEE OFFBOARDING: END-TO-END DATA FLOW
// ================================================================

// TRIGGER
// BambooHR fires webhook on employee status change or last_working_day set
BambooHR.webhook.event = 'employeeStatusChanged' | 'lastWorkingDaySet'
payload.employee_id       -> string   // e.g. '4821'
payload.full_name         -> string   // e.g. 'Jane Smith'
payload.email             -> string   // e.g. 'jane.smith@yourcompany.com'
payload.personal_email    -> string   // e.g. 'jane.smith@gmail.com'
payload.last_working_day  -> date     // e.g. '2025-04-30'
payload.manager_email     -> string   // e.g. 'mark.jones@yourcompany.com'
payload.department        -> string   // e.g. 'Sales'
payload.employment_type   -> string   // e.g. 'employee'

// SUPPLEMENTAL FETCH (before agent 1 executes)
BambooHR.GET /v1/employees/{employee_id}/timeOff/calculator
  -> leave_balance_hours: number     // e.g. 24.5

// ================================================================
// AGENT HANDOFF 1: TRIGGER -> ACCESS REVOCATION AGENT
// ================================================================

// STEP 1: Suspend Okta SSO session
Okta.POST /api/v1/users/{okta_user_id}/lifecycle/suspend
  match by: email == Okta.profile.login
  -> okta_user_id: string            // e.g. '00u1abc2defGHIJK'
  -> okta_suspended: boolean         // true on HTTP 200

// STEP 2: Disable Google Workspace account
GoogleAdmin.PATCH /admin/directory/v1/users/{userKey}
  userKey: email
  body: { suspended: true }
  -> google_disabled: boolean        // true on HTTP 200

// STEP 3: Transfer Google Drive ownership to manager
GoogleAdmin.POST /drive/v3/files/{fileId}/permissions
  transferOwnership: true
  newOwner: manager_email
  -> google_drive_transferred: boolean

// STEP 4: Set Gmail auto-reply
Gmail.PUT /gmail/v1/users/{userId}/settings/vacation
  body: {
    enableAutoReply: true,
    responseSubject: 'Out of Office',
    responseBodyHtml: env.OFFBOARD_AUTO_REPLY_BODY
  }
  -> auto_reply_set: boolean

// STEP 5: Write revocation log entry
AuditLog.INSERT {
  employee_id, okta_user_id, okta_suspended,
  google_disabled, google_drive_transferred,
  auto_reply_set, revocation_timestamp: now()
}

// Access Revocation Agent output confirmation payload assembled
agent1.output = {
  employee_id, full_name, email, personal_email,
  last_working_day, manager_email, department,
  leave_balance_hours,
  okta_suspended, okta_user_id,
  google_disabled, google_drive_transferred, auto_reply_set,
  revocation_timestamp,
  error_flags: []
}

// ================================================================
// AGENT HANDOFF 2: ACCESS REVOCATION AGENT -> TASK & NOTIFICATION AGENT
// Condition: agent1.output.okta_suspended == true
//            AND agent1.output.google_disabled == true
// On failure: retry every 5 min up to 30 min, then Slack alert
// ================================================================

// STEP 6: Create Jira offboarding board from template
Jira.POST /rest/api/3/project
  templateKey: 'HR-OFFBOARD-TEMPLATE'
  projectName: 'Offboarding - {full_name} - {last_working_day}'
  -> jira_board_url: string
  -> jira_project_key: string        // e.g. 'OFF-142'

// STEP 7: Create equipment return subtask
Jira.POST /rest/api/3/issue
  projectKey: jira_project_key
  issuetype: 'Task'
  summary: 'Equipment return - {full_name}'
  assignee: manager_email
  dueDate: last_working_day
  -> jira_equipment_task_id: string  // e.g. 'OFF-142-3'

// STEP 8: Send payroll notification to Xero
Xero.POST /api.xro/2.0/ManualJournals  (Accounting) OR
Xero.POST /payroll.xro/1.0/Employees/{employeeId}/LeaveApplications (Payroll)
  body: {
    employee_id: xero_employee_id,   // matched by email
    final_working_day: last_working_day,
    leave_balance_hours: leave_balance_hours,
    notification_note: 'Offboarding triggered - final pay action required'
  }
  -> xero_notification_sent: boolean

// STEP 9: Dispatch exit survey email
// send_date = last_working_day - 1 business day (excl. env.JURISDICTION_HOLIDAY_CALENDAR)
Gmail.POST /gmail/v1/users/me/messages/send
  to: personal_email
  subject: 'We would love your feedback'
  body: env.EXIT_SURVEY_BODY_TEMPLATE
  scheduled_send_time: exit_survey_send_date
  -> exit_survey_sent: boolean
  -> exit_survey_send_date: date

// STEP 10: Post Slack summary to HR channel
Slack.POST env.SLACK_HR_WEBHOOK
  payload: {
    text: 'Offboarding complete for {full_name} ({last_working_day})',
    blocks: [
      { okta_suspended, google_disabled, xero_notification_sent,
        exit_survey_sent, jira_board_url },
      { pending: ['Equipment return (manager action in Jira)',
                  'Exit interview (HR action)'] }
    ]
  }
  -> slack_summary_posted: boolean

// ================================================================
// AGENT HANDOFF 3: EQUIPMENT RETURN GATE (human in loop)
// Manager marks jira_equipment_task_id Done in Jira
// Jira webhook fires to automation platform endpoint /webhooks/jira-equipment-done
// Condition: issue.key == jira_equipment_task_id AND status == 'Done'
// ================================================================

// STEP 11: Close BambooHR record
BambooHR.PATCH /v1/employees/{employee_id}
  body: {
    status: 'offboarded',
    offboard_date: today()           // ISO 8601
  }
  -> bamboohr_record_closed: boolean
  -> bamboohr_close_timestamp: datetime

// STEP 12: Write final audit log entry
AuditLog.UPDATE {
  employee_id,
  bamboohr_record_closed, bamboohr_close_timestamp,
  all_steps_complete: true
}

// ================================================================
// END OF FLOW
// ================================================================
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation tool with one workflow per agent (Access Revocation Agent and Task and Notification Agent as separate workflow files). Credentials stored in a shared credential store scoped to the project. No hardcoded secrets in workflow logic. Environment variables used for all configurable values (auto-reply copy, Slack webhook URL, fallback email, holiday calendar, exit survey template).
Webhook configuration
Two inbound webhooks required. (1) BambooHR departure trigger: the automation platform exposes a public HTTPS endpoint; the BambooHR admin registers this URL under Settings > Integrations > Webhooks with the event 'Employee Status Changed'. Enable webhook signature verification and store the signing secret as env.BAMBOOHR_WEBHOOK_SECRET. (2) Jira equipment-done trigger: a second HTTPS endpoint registered in Jira under Project Settings > Webhooks, scoped to issue-updated events on project key 'HR-OFFBOARD' where status transitions to 'Done'. Both webhooks must return HTTP 200 within 3 seconds to prevent retry storms.
Templating approach
All user-facing message bodies (Gmail auto-reply, exit survey email, Slack summary, Xero payroll note) are stored as plain-text environment variables with {{placeholder}} tokens. The orchestration layer performs token substitution at runtime using values from the BambooHR payload. This allows the HR team to update message copy without touching workflow logic. Jira board structure is defined by the 'HR-OFFBOARD-TEMPLATE' project saved in the Jira workspace, not by the workflow itself.
Error logging
All step-level errors are written to a dedicated audit log table (Supabase table: offboarding_audit_log, columns: employee_id, step_name, status, error_code, error_message, timestamp). On any error, the orchestration layer also fires a Slack alert to env.SLACK_HR_WEBHOOK with the employee name, failed step, error code, and a manual action prompt. Critical failures (Okta suspension fails, BambooHR webhook cannot be parsed) trigger an additional email alert to support@gofullspec.com and the HR Manager address stored in env.HR_MANAGER_EMAIL. Retry policy: 2 automatic retries with 60-second back-off before alerting.
Testing approach
All agent flows are built and validated in sandbox environments first. BambooHR sandbox account must be provisioned with a dummy employee record before build starts. Okta Developer account used for Okta API testing. Google Workspace test user account created in the domain with no production data. Jira test project cloned from the 'HR-OFFBOARD-TEMPLATE' with key prefix 'TEST-'. Xero demo company used for payroll notification testing. End-to-end tests run with the dummy employee record to validate the full trigger-to-closure flow before any live run. See the Test and QA Plan (FS-DOC-06) for full test case coverage.
Credential inventory
BambooHR API key (env.BAMBOOHR_API_KEY), BambooHR subdomain (env.BAMBOOHR_SUBDOMAIN), BambooHR webhook signing secret (env.BAMBOOHR_WEBHOOK_SECRET), Okta API token (env.OKTA_API_TOKEN), Okta org domain (env.OKTA_DOMAIN), Google service account JSON key with domain-wide delegation (env.GOOGLE_SERVICE_ACCOUNT_JSON), Jira API token (env.JIRA_API_TOKEN), Jira base URL and project key (env.JIRA_BASE_URL, env.JIRA_OFFBOARD_PROJECT_KEY), Xero OAuth 2.0 client ID and secret (env.XERO_CLIENT_ID, env.XERO_CLIENT_SECRET), Slack incoming webhook URL (env.SLACK_HR_WEBHOOK).
Estimated total build time
Access Revocation Agent: 10 hours. Task and Notification Agent: 10 hours. End-to-end integration testing and error-path validation: 2 hours. Total: 22 hours. This matches the confirmed build_effort_hours in the project snapshot.
Before the FullSpec team can begin the Access Revocation Agent build, the following must be confirmed and supplied by your team: (1) Okta API token from a super-admin account with okta.users.manage scope, (2) Google Workspace service account with domain-wide delegation authorised by a super-admin, (3) BambooHR API key and subdomain, (4) Jira API token and confirmed 'HR-OFFBOARD-TEMPLATE' project key, (5) personal_email field confirmed as populated in BambooHR for all employees, and (6) Xero plan confirmed as Payroll or Accounting-only. Send credentials via the secure credential submission form linked in your FullSpec dashboard, not by email. Contact support@gofullspec.com with any access questions.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Employee Offboarding.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View