FS-DOC-05Technical
Integration and API Spec
Org Chart and Headcount Management
[YourCompany.com] · HR Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for every integration point in the Org Chart and Headcount Management automation. It covers authentication methods, required OAuth scopes, webhook configuration, canonical field mappings between tools, orchestration layout, credential-store structure, and defined error-handling behaviour for all integration scenarios. The FullSpec team uses this spec as the build contract; all implementation decisions must be consistent with the facts and constraints recorded here. Nothing in this document should be hardcoded into workflow logic: all credentials, IDs, and configuration values belong in the shared credential store.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by agents
Orchestration layer
Workflow automation platform hosting all three agent workflows and the shared credential store
Internal service account
N/A (build dependency)
All agents
BambooHR
HR system of record; source of all personnel change events via webhook
API key (per-account)
Essentials or above
Agent 1, Agent 2
Gusto
Payroll record destination; receives synced employment and compensation data
OAuth 2.0 (authorization code flow)
Core or above
Agent 1
Google Sheets
Live headcount tracker; rows updated on every confirmed sync and read for weekly report generation
OAuth 2.0 (Google identity)
Google Workspace (any paid tier) or personal Google account with Sheets API enabled
Agent 1, Agent 3
Lucidchart
Org chart diagram destination; nodes rewritten via REST API on each confirmed sync event
OAuth 2.0 (authorization code flow)
Team plan or above (API access required)
Agent 2
Slack
Stakeholder notification channel; receives formatted change alerts from Agent 3
OAuth 2.0 (Bot token via Slack App)
Free tier sufficient; Pro recommended for audit log retention
Agent 3
Gmail
Weekly headcount report delivery to leadership distribution list
OAuth 2.0 (Google identity, Gmail API scope)
Google Workspace Business Starter or above
Agent 3
Google Workspace (Drive)
Document filing destination for BambooHR-attached files
OAuth 2.0 (Google identity, Drive API scope)
Google Workspace Business Starter or above
Agent 3
Before you connect anything: every integration listed above must be validated against a sandbox or test account before production credentials are entered into the credential store. For BambooHR, use a test subdomain or a cloned employee record set. For Gusto, use the Gusto Developer sandbox environment. For Lucidchart, use a duplicate of the production document with a separate document ID. Production credentials must never appear in workflow logs, test runs, or version control at any point.
02Per-tool integration detail
BambooHR
Source of truth for all personnel change events. The automation platform receives webhook notifications from BambooHR on every hire, role change, or termination. The REST API is also polled as a fallback if a webhook delivery is missed.
Auth method
API key passed as Basic Auth (base64-encoded as username; password field left blank). Key is stored in the credential store as BAMBOOHR_API_KEY and retrieved at runtime.
Required scopes
BambooHR API keys carry account-level permissions. Restrict the key to a dedicated read-only integration user with access to: employees:read, webhooks:manage, fields:read. Write access is not required for BambooHR in this automation.
Webhook setup
Navigate to BambooHR Settings > API > Webhooks. Create a webhook pointing to the orchestration layer's inbound HTTPS endpoint. Select event types: Employee Added, Employee Changed, Employee Terminated. Set the secret key (stored as BAMBOOHR_WEBHOOK_SECRET). The platform validates the X-BambooHR-Signature-V2 HMAC-SHA256 header on every inbound request before processing.
Signature validation
Compute HMAC-SHA256 of the raw request body using BAMBOOHR_WEBHOOK_SECRET. Compare against the value in X-BambooHR-Signature-V2. Reject with HTTP 401 if they do not match. Never process an unvalidated payload.
Required configuration
BAMBOOHR_SUBDOMAIN stored in credential store (e.g. yourcompany). Base URL constructed at runtime as https://api.bamboohr.com/api/gateway.php/{BAMBOOHR_SUBDOMAIN}/v1/. Field list to retrieve on each event: id, firstName, lastName, jobTitle, department, employmentStatus, supervisorId, location, startDate, terminationDate, compensationChangeReason, salary.
Rate limits
BambooHR enforces a limit of 1 API request per second per account. At ~12 personnel changes per month the automation generates well under 1 request/minute on average. No throttling logic is required at current volume, but exponential backoff must still be implemented for 429 responses.
Constraints
Webhook payload field inclusion varies by account configuration. A field-mapping audit must be completed before build to confirm which fields appear in the payload versus which require a follow-up GET /employees/{id} call. Custom fields are not guaranteed across accounts.
// Inbound webhook payload (abridged)
{
"employeeId": "1042",
"action": "Changed",
"changedFields": ["jobTitle", "department", "supervisorId"],
"employee": {
"id": "1042",
"firstName": "Jane",
"lastName": "Doe",
"jobTitle": "Senior Designer",
"department": "Product",
"supervisorId": "1018",
"employmentStatus": "Active",
"startDate": "2022-03-14"
}
}
// Fallback GET endpoint
GET https://api.bamboohr.com/api/gateway.php/{subdomain}/v1/employees/{id}?fields=id,firstName,lastName,jobTitle,department,supervisorId,employmentStatus,startDate,terminationDate,salaryGusto
Payroll record destination. Agent 1 writes updated employment status, department, cost centre, and compensation data to Gusto after a BambooHR event is confirmed. Salary adjustments above a configurable threshold are routed to a human approval step before any write occurs.
Auth method
OAuth 2.0 authorization code flow. Access token and refresh token stored as GUSTO_ACCESS_TOKEN and GUSTO_REFRESH_TOKEN in the credential store. Token refresh is handled automatically by the orchestration layer when a 401 response is received.
Required scopes
employees:read, employees:write, jobs_and_compensations:read, jobs_and_compensations:write, companies:read
Webhook / trigger
Gusto is a write destination only in this automation. No inbound webhook is configured. The agent calls Gusto endpoints after receiving a confirmed BambooHR event.
Required configuration
GUSTO_COMPANY_ID stored in credential store. Base URL: https://api.gusto.com/v1/. SALARY_CHANGE_THRESHOLD_USD stored as a configurable environment variable (default: 5000). Changes at or above this threshold are held and routed to the HR Manager approval step before any Gusto write is attempted.
Key endpoints
GET /v1/companies/{company_id}/employees, PUT /v1/employees/{employee_id}, POST /v1/employees/{employee_id}/jobs, PUT /v1/employees/{employee_id}/jobs/{job_id}/compensations
Rate limits
Gusto enforces 60 requests/minute per access token. At 12 changes/month the automation is well within this limit. No throttling is required. Backoff on 429 is still implemented (see section 05).
Constraints
Gusto requires a valid job_id before a compensation record can be updated. The agent must retrieve the employee's current job_id via GET before attempting a compensation PUT. Terminations in Gusto require an explicit termination_effective_date and cannot be reversed via API without manual intervention.
// Write employment update
PUT https://api.gusto.com/v1/employees/{employee_id}
{
"department": "Product",
"work_email": "jane.doe@yourcompany.com"
}
// Write compensation update (only after approval if above threshold)
PUT https://api.gusto.com/v1/employees/{employee_id}/jobs/{job_id}/compensations
{
"rate": "95000.00",
"payment_unit": "Year",
"flsa_status": "Exempt"
}Google Sheets
Live headcount tracker. Agent 1 updates the relevant employee row on every confirmed sync. Agent 3 reads the sheet every Monday morning to generate the leadership headcount report. The sheet schema must match the canonical column structure defined below.
Auth method
OAuth 2.0 via Google identity. Service account JSON key stored as GOOGLE_SERVICE_ACCOUNT_JSON in the credential store. The service account is granted Editor access to the headcount spreadsheet only.
Required scopes
https://www.googleapis.com/auth/spreadsheets, https://www.googleapis.com/auth/drive.file
Webhook / trigger
No webhook. Agent 1 writes to Sheets after a BambooHR event is processed. Agent 3 is triggered by a scheduled cron every Monday at 07:00 in the configured timezone.
Required configuration
HEADCOUNT_SHEET_ID stored in credential store (the spreadsheet ID from the Sheets URL). HEADCOUNT_TAB_NAME stored as a configurable variable (default: Headcount). REPORT_TIMEZONE stored as a configurable variable (default: America/New_York). Column index positions must be stored as named constants, not hardcoded integers.
Sheet structure
Row 1 is a frozen header row. Columns (A through L): employee_id, first_name, last_name, job_title, department, employment_status, manager_id, location, start_date, termination_date, fte_status, last_updated_at. The automation matches rows by employee_id in column A. No duplicate employee_id values are permitted.
Rate limits
Google Sheets API enforces 300 read requests/minute and 300 write requests/minute per project. At 12 changes/month plus one weekly read, the automation is far below these limits. No throttling required.
Constraints
The service account must be explicitly shared on the spreadsheet. Sharing via Google Drive folder inheritance alone is not reliable. If the sheet is moved or renamed, the HEADCOUNT_SHEET_ID reference in the credential store must be updated manually.
// Find row by employee_id
GET https://sheets.googleapis.com/v4/spreadsheets/{HEADCOUNT_SHEET_ID}/values/{HEADCOUNT_TAB_NAME}!A:A
// Update matched row
PUT https://sheets.googleapis.com/v4/spreadsheets/{HEADCOUNT_SHEET_ID}/values/{HEADCOUNT_TAB_NAME}!A{row}:L{row}
Body: [[employee_id, first_name, last_name, job_title, department, employment_status, manager_id, location, start_date, termination_date, fte_status, ISO8601_timestamp]]
// Weekly read for report generation (Agent 3)
GET https://sheets.googleapis.com/v4/spreadsheets/{HEADCOUNT_SHEET_ID}/values/{HEADCOUNT_TAB_NAME}!A2:LIntegration and API SpecPage 1 of 3
FS-DOC-05Technical
Lucidchart
Org chart diagram destination. Agent 2 reads the current document structure after a confirmed Headcount Sync Agent completion, locates the affected employee node, and rewrites title, department, and reporting line (parent shape) via the Lucidchart REST API.
Auth method
OAuth 2.0 authorization code flow. Access token and refresh token stored as LUCIDCHART_ACCESS_TOKEN and LUCIDCHART_REFRESH_TOKEN. Token refresh triggered automatically on 401.
Required scopes
lucidchart.document:read, lucidchart.document:write
Webhook / trigger
No inbound webhook from Lucidchart. Agent 2 is triggered by an internal completion event published by Agent 1 (Headcount Sync Agent) to the orchestration layer's internal event bus after a confirmed write to both Gusto and Google Sheets.
Required configuration
LUCIDCHART_DOCUMENT_ID stored in credential store (the production org chart document). LUCIDCHART_TEMPLATE_SHAPE_LAYER stored as a configurable variable identifying the layer name containing employee boxes (default: Org Nodes). Employee shapes must carry a custom data property employee_id matching BambooHR IDs. This mapping must be validated during the Discovery stage before build commences.
Key endpoints
GET /documents/{documentId} to retrieve current structure; PATCH /documents/{documentId}/pages/{pageId}/shapes/{shapeId} to update a shape's text content, custom data, and parent reference; POST /documents/{documentId}/pages/{pageId}/shapes to create a new employee node for new hires.
Rate limits
Lucidchart API enforces 60 requests/minute per OAuth token. Each personnel change triggers approximately 3-5 API calls. At 12 changes/month the automation is well within limits. No throttling required at current volume.
Constraints
The Lucidchart org chart must use consistent shape naming and layer structure before the agent can reliably locate and update nodes. Ad-hoc diagrams built without a consistent employee_id custom data property will require a one-time remediation pass before go-live. The Team plan or above is required for API access; the Free plan does not expose the REST API.
// Locate shape by employee_id custom property
GET /documents/{LUCIDCHART_DOCUMENT_ID}
-> Traverse pages[].shapes[] where customData.employee_id == bamboohr_employee_id
// Update existing shape
PATCH /documents/{documentId}/pages/{pageId}/shapes/{shapeId}
{
"text": "Jane Doe\nSenior Designer",
"customData": { "employee_id": "1042", "department": "Product" },
"parentId": "{supervisor_shape_id}"
}
// Create new shape for new hire
POST /documents/{documentId}/pages/{pageId}/shapes
{
"type": "employee-box",
"text": "Jane Doe\nSenior Designer",
"customData": { "employee_id": "1042", "department": "Product" },
"parentId": "{supervisor_shape_id}"
}Slack
Stakeholder notification channel. Agent 3 sends formatted change alert messages to configured Slack channels after every confirmed sync event. The Slack App must be installed to the workspace and granted to the channels it posts in.
Auth method
OAuth 2.0 Bot token. Token stored as SLACK_BOT_TOKEN in the credential store. The Slack App is created in the workspace's App Directory with bot token scopes only.
Required scopes
chat:write, chat:write.public, channels:read, users:read, users:read.email
Webhook / trigger
No inbound webhook from Slack. Outbound messages are sent via the Slack Web API. Agent 3 is triggered by the internal completion event from Agent 1 for change alerts, and by the Monday 07:00 cron for the weekly report.
Required configuration
SLACK_HR_CHANNEL_ID, SLACK_IT_CHANNEL_ID, SLACK_FINANCE_CHANNEL_ID, and SLACK_LEADERSHIP_CHANNEL_ID stored in the credential store. Channel IDs (not names) must be used to avoid breakage on channel renames. Message template text is stored as a configurable variable, not hardcoded in workflow logic.
Rate limits
Slack Web API enforces 1 message per second per channel (Tier 3 methods). At 12 change events per month the automation is within limits. No throttling required.
Constraints
The Slack App bot must be invited to each target channel before it can post. Public channels can be reached with chat:write.public, but private channels require an explicit /invite. Channel IDs must be confirmed during the Discovery stage and stored before build.
// Send change notification
POST https://slack.com/api/chat.postMessage
Authorization: Bearer {SLACK_BOT_TOKEN}
{
"channel": "{SLACK_HR_CHANNEL_ID}",
"text": "Personnel change recorded",
"blocks": [
{ "type": "section", "text": { "type": "mrkdwn", "text": "*Jane Doe* has been updated to *Senior Designer* in *Product*, effective 2024-04-16." } },
{ "type": "context", "elements": [{ "type": "mrkdwn", "text": "Source: BambooHR | Synced to: Gusto, Sheets, Lucidchart" }] }
]
}Gmail
Weekly leadership headcount report delivery. Agent 3 reads the current headcount data from Google Sheets every Monday morning, composes a summary email, and sends it to the leadership distribution list via the Gmail API.
Auth method
OAuth 2.0 via Google identity. The same service account used for Google Sheets is granted domain-wide delegation to send email as the designated HR sender address. GMAIL_SENDER_ADDRESS stored in the credential store.
Required scopes
https://www.googleapis.com/auth/gmail.send
Webhook / trigger
No inbound webhook. Agent 3 sends outbound email on the Monday 07:00 cron schedule.
Required configuration
GMAIL_SENDER_ADDRESS (the HR Manager's address used as the From address), LEADERSHIP_DISTRIBUTION_EMAIL (the group address or comma-separated list) both stored in the credential store. Email subject line template stored as a configurable variable: "Weekly Headcount Report - {ISO_WEEK_DATE}". Body is generated dynamically from Sheets data.
Rate limits
Gmail API enforces 250 quota units per second per user and a daily send limit of 2,000 messages for Google Workspace accounts. One email per week is negligible. No throttling required.
Constraints
Domain-wide delegation must be configured in the Google Workspace Admin console and the service account must be authorised for the sender address. If the sender address changes, the credential store entry and Admin console delegation must both be updated.
// Send weekly report email
POST https://gmail.googleapis.com/gmail/v1/users/{GMAIL_SENDER_ADDRESS}/messages/send
{
"raw": "<base64url-encoded RFC 2822 message>"
}
// RFC 2822 message structure
From: {GMAIL_SENDER_ADDRESS}
To: {LEADERSHIP_DISTRIBUTION_EMAIL}
Subject: Weekly Headcount Report - 2024-W16
Content-Type: text/html; charset=utf-8
<body>... dynamically generated headcount summary table ...</body>03Field mappings between tools
The following tables define the exact field mappings for each agent handoff. All field names are written in monospace as they appear in the source and destination API payloads. Any field not listed here is not mapped and should not be written to a destination system.
Agent 1 handoff: BambooHR to Gusto
Source tool
Source field
Destination tool
Destination field
BambooHR
`employee.id`
Gusto
`employee_id` (looked up via GET /employees?email)
BambooHR
`employee.firstName`
Gusto
`first_name`
BambooHR
`employee.lastName`
Gusto
`last_name`
BambooHR
`employee.jobTitle`
Gusto
`jobs[0].title`
BambooHR
`employee.department`
Gusto
`department`
BambooHR
`employee.employmentStatus`
Gusto
`onboarding_status` / termination record
BambooHR
`employee.terminationDate`
Gusto
`termination.effective_date`
BambooHR
`employee.salary`
Gusto
`compensations[0].rate` (held for approval if above threshold)
BambooHR
`employee.compensationChangeReason`
Gusto
`compensations[0].payment_unit` (mapped: Salary -> Year)
Agent 1 handoff: BambooHR to Google Sheets
Source tool
Source field
Destination tool
Destination field
BambooHR
`employee.id`
Google Sheets
`employee_id` (column A, used as row key)
BambooHR
`employee.firstName`
Google Sheets
`first_name` (column B)
BambooHR
`employee.lastName`
Google Sheets
`last_name` (column C)
BambooHR
`employee.jobTitle`
Google Sheets
`job_title` (column D)
BambooHR
`employee.department`
Google Sheets
`department` (column E)
BambooHR
`employee.employmentStatus`
Google Sheets
`employment_status` (column F)
BambooHR
`employee.supervisorId`
Google Sheets
`manager_id` (column G)
BambooHR
`employee.location`
Google Sheets
`location` (column H)
BambooHR
`employee.startDate`
Google Sheets
`start_date` (column I)
BambooHR
`employee.terminationDate`
Google Sheets
`termination_date` (column J)
Derived
`employmentStatus == Active ? 1.0 : 0.0`
Google Sheets
`fte_status` (column K)
System
`NOW()` (ISO 8601)
Google Sheets
`last_updated_at` (column L)
Agent 2 handoff: BambooHR (via Agent 1 completion event) to Lucidchart
Source tool
Source field
Destination tool
Destination field
BambooHR
`employee.id`
Lucidchart
`shape.customData.employee_id` (shape lookup key)
BambooHR
`employee.firstName` + `employee.lastName`
Lucidchart
`shape.text` (line 1: full name)
BambooHR
`employee.jobTitle`
Lucidchart
`shape.text` (line 2: job title)
BambooHR
`employee.department`
Lucidchart
`shape.customData.department`
BambooHR
`employee.supervisorId`
Lucidchart
`shape.parentId` (resolved via customData.employee_id lookup on supervisor)
Agent 3 handoff: Google Sheets to Gmail (weekly report)
Source tool
Source field
Destination tool
Destination field
Google Sheets
`department` (column E, grouped)
Gmail
Report section header per department
Google Sheets
`employment_status` (column F, count Active)
Gmail
Total active headcount figure
Google Sheets
`fte_status` (column K, sum)
Gmail
Total FTE count
Google Sheets
`termination_date` (column J, current week)
Gmail
Departures this week row
Google Sheets
`start_date` (column I, current week)
Gmail
New starters this week row
Google Sheets
`last_updated_at` (column L, MAX)
Gmail
Report data freshness timestamp
Integration and API SpecPage 2 of 3
FS-DOC-05Technical
04Build stack and orchestration
Orchestration layout
Three discrete workflow definitions: one per agent (Headcount Sync Agent, Org Chart Update Agent, Notification and Reporting Agent). Each workflow is independently deployable and independently testable. All three share a single credential store. No credentials are duplicated across workflows.
Inter-agent communication
Agent 1 (Headcount Sync) publishes a structured completion event to the orchestration layer's internal event bus upon successful writes to both Gusto and Google Sheets. Agent 2 (Org Chart Update) subscribes to this event as its sole trigger. Agent 3 (Notification and Reporting) also subscribes to this event for change alerts, and separately to the Monday 07:00 cron for weekly reports.
Agent 1 trigger mechanism
Inbound webhook from BambooHR (push). The orchestration layer exposes a stable HTTPS endpoint. Signature validation (HMAC-SHA256 against BAMBOOHR_WEBHOOK_SECRET) is applied on every inbound request before the workflow proceeds. A fallback poll runs every 6 hours via the BambooHR REST API to catch any missed webhook deliveries.
Agent 2 trigger mechanism
Internal event subscription (push from Agent 1 completion event). No external webhook. The event payload carries the mapped employee data object so Agent 2 does not need to re-call BambooHR independently.
Agent 3 trigger mechanism (change alerts)
Internal event subscription (push from Agent 1 completion event). Slack notification is sent within seconds of Agent 1 publishing its completion event.
Agent 3 trigger mechanism (weekly report)
Scheduled cron: every Monday at 07:00 in REPORT_TIMEZONE. The cron reads live data from Google Sheets at the time of execution; no cached snapshot is used.
Salary approval routing
Agent 1 evaluates the incoming salary value against SALARY_CHANGE_THRESHOLD_USD before any Gusto write. If the change is at or above the threshold, the workflow pauses and routes to a manual approval step (email to GMAIL_SENDER_ADDRESS with an approve/reject link). The Gusto write only proceeds after explicit approval. If no response is received within 24 hours, the workflow sends a reminder and waits a further 24 hours before escalating.
Environment separation
Separate credential store entries are maintained for sandbox and production environments. Workflow definitions reference environment variables for all credential keys. Switching from sandbox to production requires only a credential store environment toggle, not a workflow edit.
Logging
Every workflow execution logs: trigger timestamp, event type, employee ID, fields changed, each integration call (endpoint, HTTP status, response time), and final outcome (success / approval-pending / failed). Logs are retained for a minimum of 90 days. All logs must be scrubbed of salary values before writing to any log store.
Credential store contents (all values populated before any workflow is activated):
All values stored in the orchestration layer's encrypted credential store. Never commit these values to version control or include them in workflow logic.
// BambooHR
BAMBOOHR_API_KEY=<api-key-from-bamboohr-integration-user>
BAMBOOHR_SUBDOMAIN=<yourcompany>
BAMBOOHR_WEBHOOK_SECRET=<hmac-secret-set-in-bamboohr-webhook-settings>
// Gusto
GUSTO_ACCESS_TOKEN=<oauth-access-token>
GUSTO_REFRESH_TOKEN=<oauth-refresh-token>
GUSTO_COMPANY_ID=<gusto-company-uuid>
SALARY_CHANGE_THRESHOLD_USD=5000
// Google (Sheets + Drive + Gmail)
GOOGLE_SERVICE_ACCOUNT_JSON=<json-key-file-contents>
HEADCOUNT_SHEET_ID=<google-sheets-spreadsheet-id>
HEADCOUNT_TAB_NAME=Headcount
GMAIL_SENDER_ADDRESS=hr@yourcompany.com
LEADERSHIP_DISTRIBUTION_EMAIL=leadership@yourcompany.com
REPORT_TIMEZONE=America/New_York
// Lucidchart
LUCIDCHART_ACCESS_TOKEN=<oauth-access-token>
LUCIDCHART_REFRESH_TOKEN=<oauth-refresh-token>
LUCIDCHART_DOCUMENT_ID=<production-org-chart-document-id>
LUCIDCHART_TEMPLATE_SHAPE_LAYER=Org Nodes
// Slack
SLACK_BOT_TOKEN=xoxb-<slack-bot-token>
SLACK_HR_CHANNEL_ID=C0XXXXXXXXX
SLACK_IT_CHANNEL_ID=C0XXXXXXXXX
SLACK_FINANCE_CHANNEL_ID=C0XXXXXXXXX
SLACK_LEADERSHIP_CHANNEL_ID=C0XXXXXXXXX
Salary values (the incoming salary field from BambooHR and the rate written to Gusto) must never appear in workflow execution logs, Slack messages, or email bodies other than the dedicated approval email sent to the HR Manager. Log entries involving compensation changes must record only the event type and the outcome (approved / rejected / pending), not the monetary value.
05Error handling and retry logic
Every integration point has a defined failure behaviour. Unhandled exceptions must never fail silently. All retries use exponential backoff starting at 30 seconds, doubling on each attempt, with a maximum of 4 attempts before the workflow moves to the defined fallback. After all retries are exhausted, the workflow logs the failure at ERROR level, sends an alert to SLACK_HR_CHANNEL_ID, and halts the affected branch without rolling back already-completed writes (partial completion is logged explicitly).
Integration
Scenario
Required behaviour
BambooHR webhook inbound
Signature validation fails (HMAC mismatch)
Reject with HTTP 401. Log the raw headers (not body). Do not process the payload. Send alert to SLACK_HR_CHANNEL_ID. No retry; the source must resend.
BambooHR webhook inbound
Webhook delivery missed (no event received for expected change)
Fallback poll runs every 6 hours. Compares BambooHR employee list against last-known state stored in the orchestration layer. If a discrepancy is found, treats it as a missed event and triggers Agent 1 normally.
BambooHR REST API (fallback GET)
HTTP 429 rate limit response
Backoff: wait 60 seconds, retry up to 4 times. If all retries fail, log ERROR and send Slack alert. Human review required before next poll cycle.
Gusto API write
HTTP 401 (token expired)
Trigger OAuth token refresh using GUSTO_REFRESH_TOKEN. Retry the original request immediately after refresh. If refresh fails, log ERROR, send Slack alert, and halt the Gusto write branch. Google Sheets write is not blocked.
Gusto API write
HTTP 422 (validation error, e.g. missing job_id)
Log full response body at ERROR level. Do not retry. Send Slack alert to SLACK_HR_CHANNEL_ID with the specific validation error. HR Manager must resolve manually in Gusto and confirm via Slack before the automation marks the event complete.
Gusto API write
Salary change above threshold, no approval received within 48 hours
After 24 hours send a reminder email. After 48 hours without response, escalate to SLACK_LEADERSHIP_CHANNEL_ID and mark the event as APPROVAL_TIMEOUT. Do not write to Gusto. Log the event for manual resolution.
Google Sheets write
Employee row not found by employee_id lookup
If the event type is New Hire, append a new row. If the event type is Changed or Terminated and no row exists, log a WARNING, send Slack alert, and append a new row with a flag column value of RECONCILIATION_NEEDED. Do not silently skip.
Google Sheets write
HTTP 403 (service account permission denied)
Log ERROR immediately. Do not retry (permission errors will not self-resolve). Send Slack alert. Human must confirm the service account is still shared on the spreadsheet and re-run the event manually.
Lucidchart API
Employee shape not found by employee_id custom property
If event type is New Hire, create a new shape. If event type is Changed or Terminated and shape is missing, log WARNING, send Slack alert to SLACK_HR_CHANNEL_ID, and skip the Lucidchart update (do not halt the full workflow). HR must locate or create the shape manually.
Lucidchart API
HTTP 401 (token expired)
Trigger OAuth token refresh using LUCIDCHART_REFRESH_TOKEN. Retry the original request once after refresh. If refresh fails, log ERROR and send Slack alert. The Lucidchart update is deferred; all other agents continue.
Slack API
HTTP 429 (rate limited) or message delivery failure
Retry with 1-second backoff up to 3 times. If all retries fail, log ERROR and write the unsent notification to a FAILED_NOTIFICATIONS table in the orchestration layer for manual dispatch. Do not silently discard.
Gmail API
Weekly report send failure (any 4xx or 5xx response)
Retry with exponential backoff (30 s, 60 s, 120 s, 240 s). If all retries fail, log ERROR and send a Slack alert to SLACK_HR_CHANNEL_ID with the Sheets data attached as a fallback so the report can be sent manually. Do not silently skip the weekly report.
Partial completion must always be logged explicitly. If Agent 1 successfully writes to Google Sheets but the Gusto write fails, the log entry must record which systems were updated and which were not. Agent 2 and Agent 3 receive the completion event only after both Gusto and Sheets writes are confirmed successful. If either fails, the completion event is not published and neither downstream agent fires.
Technical support
support@gofullspec.com
Document reference
FS-DOC-05 / Org Chart and Headcount Management / Integration and API Spec
Integration and API SpecPage 3 of 3