FS-DOC-05Technical
Integration and API Spec
Leave and Absence Management
[YourCompany.com] · HR Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for every integration point in the Leave and Absence Management automation. It covers authentication, required scopes, webhook configuration, field mappings, credential store contents, rate limits, and failure handling for all five connected tools plus the orchestration layer. The FullSpec team uses this specification to build, configure, and validate the three-agent workflow. Your team should treat this as the source of truth for any post-launch changes or debugging sessions.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by agents
BambooHR
Employee records, leave balance reads and writes
OAuth 2.0 / API key (per account)
Essentials or above (API access required)
Agent 1, Agent 3
Google Calendar
Conflict detection reads; approved-leave event writes
OAuth 2.0 (service account recommended)
Any Google Workspace plan
Agent 1, Agent 3
Slack
Manager approval messages; employee and team notifications
OAuth 2.0 via custom Slack app
Pro or above (custom apps require paid plan)
Agent 2, Agent 3
Gmail
Fallback decline notification to employee
OAuth 2.0 (service account or delegated)
Google Workspace Business Starter or above
Agent 2
Gusto
Payroll leave deduction logging on approval
OAuth 2.0 (partner token flow)
Core or above (API access via partner enrollment)
Agent 3
Workflow automation tool
Orchestration layer: triggers, routing, credential store, retry logic
Platform-native credential manager
Subscription that supports webhook listeners and scheduled polls
All agents
Before you connect anything: create sandbox or test credentials for every tool and validate all connections end-to-end in a non-production environment before switching to production credentials. BambooHR and Gusto in particular do not offer a dedicated sandbox; use a separate test company account or a staging subdomain where available. Never hardcode production tokens in workflow steps.
02Per-tool integration detail
BambooHR
Used by Agent 1 (Leave Intake and Balance Agent) to read employee leave balances and by Agent 3 (Post-Approval Sync Agent) to deduct approved days and update the leave record. All calls use the BambooHR REST API v1 against the company-specific subdomain.
Auth method
API key authentication. The API key is generated per BambooHR user account under Account Settings. Pass the key as the username in HTTP Basic Auth with any string as the password. Store the key in the credential store as BAMBOOHR_API_KEY. The company subdomain is stored separately as BAMBOOHR_SUBDOMAIN.
Required scopes
BambooHR uses permission sets rather than OAuth scopes. The API user account must have: 'Employee Access' (read) for profile and leave balance fields; 'Time Off' (read and write) for balance retrieval and deduction; 'Reports' (read) if balance data is pulled via a custom report endpoint.
Webhook / trigger setup
BambooHR does not provide outbound webhooks for leave balance changes. Agent 1 polls the Time Off balance endpoint on demand when a new request form submission arrives. No standing webhook is required on the BambooHR side.
Required configuration
Store BAMBOOHR_SUBDOMAIN (e.g. yourcompany) and BAMBOOHR_API_KEY in the credential store. Identify and store the numeric leave type IDs (BAMBOOHR_LEAVE_TYPE_ANNUAL, BAMBOOHR_LEAVE_TYPE_SICK, etc.) by querying GET /v1/meta/time_off/types/ during setup. Do not hardcode IDs in workflow steps.
Rate limits
BambooHR enforces a limit of approximately 500 API calls per day per company at standard plans. At 40 requests per month (roughly 2 per day), current volume is well within this limit. Throttling logic is not required at current volume but should be added as a safeguard if request volume exceeds 200 per month.
Constraints
The API user must be an active employee account with HR admin permissions. Service accounts are not a native BambooHR concept; use a dedicated HR admin user. Leave balance deductions via the API write to the time-off ledger and are immediately visible to the employee in their BambooHR portal, so do not call the write endpoint until manager approval is confirmed.
// Balance read (Agent 1)
GET https://{BAMBOOHR_SUBDOMAIN}.bamboohr.com/api/gateway.php/{BAMBOOHR_SUBDOMAIN}/v1/employees/{employee_id}/time_off/calculator/
-> returns: accrued, used, scheduled, balance per leave type
// Balance deduction (Agent 3)
POST https://{BAMBOOHR_SUBDOMAIN}.bamboohr.com/api/gateway.php/{BAMBOOHR_SUBDOMAIN}/v1/employees/{employee_id}/time_off/requests/
body: { start, end, timeOffTypeId, amount, status: 'approved', note }
-> returns: request ID, updated balanceGoogle Calendar
Used by Agent 1 to scan the shared team calendar for coverage conflicts during the requested leave dates, and by Agent 3 to create an all-day absence event on approval. A Google Cloud service account with domain-wide delegation is the recommended auth method to avoid per-user OAuth consent flows.
Auth method
OAuth 2.0 via a Google Cloud service account with domain-wide delegation. Download the service account JSON key and store it as GOOGLE_SERVICE_ACCOUNT_JSON in the credential store. Delegate access to the HR admin user's Google Workspace identity so the service account can act on behalf of that user.
Required scopes
https://www.googleapis.com/auth/calendar.readonly (conflict check reads by Agent 1); https://www.googleapis.com/auth/calendar.events (event creation by Agent 3). Both scopes must be granted in the Google Workspace Admin console under domain-wide delegation for the service account client ID.
Webhook / trigger setup
Google Calendar is not a trigger in this workflow; it is called on demand by Agent 1 (read) and Agent 3 (write). No push notification channel is required. If future logic needs to react to calendar changes, use the Calendar API push notifications endpoint (POST /calendars/{calendarId}/events/watch) with HMAC-SHA256 signature validation on the receiving webhook endpoint.
Required configuration
Store GOOGLE_TEAM_CALENDAR_ID (the full calendar ID of the shared team absence calendar, e.g. yourcompany.com_abc123@group.calendar.google.com) in the credential store. Store GOOGLE_CONFLICT_THRESHOLD as an integer representing the maximum number of concurrent absences allowed before a conflict is flagged. Confirm both values with HR before build starts.
Rate limits
Google Calendar API enforces 1,000,000 queries per day per project and 500 queries per 100 seconds per user. At 40 leave requests per month (80 API calls total: 1 read and 1 write per request), current volume is negligible. No throttling is needed.
Constraints
The shared team calendar must be accessible to the service account identity. Verify sharing settings before build. All-day events must be created with date values (not dateTime) in the event body to display correctly in Google Calendar. Event summary format must follow the agreed naming convention stored in GOOGLE_EVENT_SUMMARY_TEMPLATE.
// Conflict check (Agent 1)
GET https://www.googleapis.com/calendar/v3/calendars/{GOOGLE_TEAM_CALENDAR_ID}/events
params: timeMin={leave_start}T00:00:00Z, timeMax={leave_end}T23:59:59Z, singleEvents=true
-> returns: list of overlapping events with attendees
// Event creation (Agent 3)
POST https://www.googleapis.com/calendar/v3/calendars/{GOOGLE_TEAM_CALENDAR_ID}/events
body: { summary: '{employee_name} - {leave_type}', start: { date }, end: { date }, description: 'Approved via Leave Management automation' }
-> returns: event.id stored for audit logSlack
Used by Agent 2 (Approval Routing Agent) to deliver a structured approval request to the line manager with interactive approve and decline buttons, and by Agent 3 (Post-Approval Sync Agent) to send a confirmation DM to the employee and a notice to the team channel. Requires a custom Slack app installed to the workspace.
Auth method
OAuth 2.0 via a custom Slack app. Create the app at api.slack.com/apps, complete the OAuth installation to the target workspace, and store the resulting Bot Token (xoxb-...) as SLACK_BOT_TOKEN in the credential store. Do not use user tokens or legacy webhook URLs for new builds.
Required scopes
chat:write (send messages to channels and DMs); im:write (open DM channels for employee notifications); commands (if slash commands are used for ad-hoc lookups, optional); blocks:write is implicit via chat:write. For interactive components (approve/decline buttons): the app must have an Interactivity Request URL configured pointing to the orchestration layer's webhook endpoint.
Webhook / trigger setup
The Slack app must have Interactivity enabled in the app settings. Set the Request URL to the orchestration layer's inbound webhook (e.g. https://automation.yourcompany.com/webhooks/slack-interactions). Slack signs all interaction payloads with the app's Signing Secret; the orchestration layer must validate each request by computing HMAC-SHA256 over the raw request body using SLACK_SIGNING_SECRET before processing. Reject any payload where the timestamp header is older than 5 minutes to prevent replay attacks.
Required configuration
Store SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, SLACK_APPROVAL_CHANNEL_PREFIX (if per-team channels are used), and SLACK_TEAM_CHANNEL_ID (the general team absence channel) in the credential store. Manager Slack user IDs must be resolvable from BambooHR manager field at runtime via the Slack users.lookupByEmail API call; do not hardcode manager IDs.
Rate limits
Slack API Tier 3 methods (chat.postMessage) allow 50 calls per minute. At 40 requests per month, peak load is a fraction of this limit. No throttling is needed at current volume.
Constraints
Interactive button payloads expire after 30 minutes by default. If the manager does not respond within 30 minutes, the workflow must handle a stale payload gracefully (see error handling section). The Slack app must be installed by a Workspace Admin. All Block Kit message structures must be validated against the Block Kit Builder before deployment to avoid silent render failures.
// Approval request (Agent 2)
POST https://slack.com/api/chat.postMessage
headers: Authorization: Bearer {SLACK_BOT_TOKEN}
body: { channel: '{manager_slack_id}', blocks: [ header, section(employee, dates, leave_type, balance), actions(approve_button, decline_button) ] }
-> returns: ts (message timestamp, stored as PENDING_APPROVAL_TS for correlation)
// Interaction callback received (Agent 2 webhook handler)
POST {SLACK_INTERACTIVITY_WEBHOOK_URL}
payload: { type: 'block_actions', actions: [{ action_id: 'approve|decline', value: '{request_id}' }], user: { id, name } }
-> validated by HMAC-SHA256 against SLACK_SIGNING_SECRET
// Employee DM and team channel post (Agent 3)
POST https://slack.com/api/chat.postMessage (x2: employee DM and team channel)Integration and API SpecPage 1 of 4
FS-DOC-05Technical
Gmail
Used by Agent 2 as a fallback notification channel when a leave request is declined due to insufficient balance or a coverage conflict. The Gmail send is triggered on the decline path only and delivers a formatted outcome email to the employee's work address.
Auth method
OAuth 2.0 using a Google Workspace service account with domain-wide delegation, or a dedicated HR Gmail account with an OAuth 2.0 refresh token. Store credentials as GMAIL_OAUTH_CLIENT_ID, GMAIL_OAUTH_CLIENT_SECRET, and GMAIL_OAUTH_REFRESH_TOKEN in the credential store. The sending address is stored as GMAIL_SENDER_ADDRESS.
Required scopes
https://www.googleapis.com/auth/gmail.send (send-only; do not request broader mail scopes). If using delegated access, the scope must be granted in Google Workspace Admin for the service account client ID.
Webhook / trigger setup
Gmail is not a trigger in this workflow. It is called as an action on the decline branch of Agent 2. No webhook or poll is required on the Gmail side.
Required configuration
Store GMAIL_SENDER_ADDRESS (e.g. hr-notifications@yourcompany.com) and GMAIL_DECLINE_TEMPLATE_ID in the credential store. The decline email template must be stored as an HTML string in the credential store or a versioned template file; it must include placeholders {{employee_name}}, {{leave_type}}, {{start_date}}, {{end_date}}, and {{decline_reason}}. Do not hardcode template HTML in workflow steps.
Rate limits
Gmail API enforces 250 quota units per user per second and a daily sending limit of 2,000 messages per Google Workspace account. At 40 requests per month, volume is negligible. No throttling is needed.
Constraints
The Gmail API send call requires the message to be base64url-encoded RFC 2822 format. The orchestration layer must construct the raw message string correctly before calling the API. Sending address must match the authenticated account or a permitted alias; mismatches cause a 403 error.
// Decline notification (Agent 2, decline branch only)
POST https://gmail.googleapis.com/gmail/v1/users/{GMAIL_SENDER_ADDRESS}/messages/send
headers: Authorization: Bearer {access_token}
body: { raw: base64url( RFC2822 message: To, From, Subject, Content-Type, HTML body with filled placeholders ) }
-> returns: message.id stored for audit logGusto
Used exclusively by Agent 3 (Post-Approval Sync Agent) to log approved leave in the payroll system so that any required deductions or accrual adjustments are captured before the next pay run closes. Gusto API access requires enrollment in the Gusto Partner Program or use of a company-level API token.
Auth method
OAuth 2.0 using the Gusto Partner OAuth flow. Store GUSTO_CLIENT_ID, GUSTO_CLIENT_SECRET, and GUSTO_REFRESH_TOKEN in the credential store. Access tokens expire after 2 hours; the orchestration layer must implement automatic token refresh using the refresh token before each API call. Company UUID is stored as GUSTO_COMPANY_UUID.
Required scopes
employees:read (resolve employee ID from BambooHR employee ID or email); payroll:write (log time off entries for payroll); company:read (validate company UUID on initial setup). Scopes are requested during the OAuth authorization code flow.
Webhook / trigger setup
Gusto is not a trigger in this workflow. Agent 3 calls the Gusto API as a write action after manager approval is confirmed. Gusto does provide webhook events for payroll state changes, but these are not used in this automation.
Required configuration
Store GUSTO_COMPANY_UUID and GUSTO_LEAVE_TYPE_MAP (a JSON object mapping BambooHR leave type IDs to Gusto time-off policy IDs, e.g. {"annual": "gusto-policy-uuid-001", "sick": "gusto-policy-uuid-002"}) in the credential store. The leave type map must be confirmed with HR and Gusto config before build. Do not hardcode policy UUIDs in workflow steps.
Rate limits
Gusto API is rate-limited to 60 requests per minute per OAuth token. At 40 payroll log calls per month, current volume is well within limits. No throttling is needed at current volume.
Constraints
Gusto time-off entries cannot be deleted via API once submitted to a processed payroll run. The workflow must not write to Gusto until the BambooHR balance deduction has succeeded, ensuring records stay consistent. If the BambooHR write fails, the Gusto write must be skipped and an alert raised (see error handling). Gusto API is only available in the US.
// Employee lookup (Agent 3)
GET https://api.gusto.com/v1/companies/{GUSTO_COMPANY_UUID}/employees
params: email={employee_email}
-> returns: employee.uuid stored as gusto_employee_uuid
// Time-off entry write (Agent 3)
POST https://api.gusto.com/v1/companies/{GUSTO_COMPANY_UUID}/time_off_requests
body: { employee_uuid: gusto_employee_uuid, time_off_type_uuid: GUSTO_LEAVE_TYPE_MAP[leave_type], start_date, end_date, status: 'approved', days_count }
-> returns: time_off_request.uuid stored for audit log03Field mappings between tools
The following tables define the exact field mappings for each agent handoff point in the workflow. All field names are given in their native monospace form as they appear in the API payload or form schema.
Agent 1 handoff: Leave request form to BambooHR balance query
Source tool
Source field
Destination tool
Destination field
Leave request form
`employee_id`
BambooHR API
`{employee_id}` in path parameter
Leave request form
`leave_type`
BambooHR API
`timeOffTypeId` (resolved via BAMBOOHR_LEAVE_TYPE map)
Leave request form
`start_date`
BambooHR API
`start` (ISO 8601 date)
Leave request form
`end_date`
BambooHR API
`end` (ISO 8601 date)
Leave request form
`employee_email`
Slack API
`users.lookupByEmail` -> `user.id`
Leave request form
`manager_email`
Slack API
`users.lookupByEmail` -> `user.id`
Agent 1 handoff: Leave request form and BambooHR response to Google Calendar conflict check
Source tool
Source field
Destination tool
Destination field
Leave request form
`start_date`
Google Calendar API
`timeMin` (appended T00:00:00Z)
Leave request form
`end_date`
Google Calendar API
`timeMax` (appended T23:59:59Z)
Credential store
`GOOGLE_TEAM_CALENDAR_ID`
Google Calendar API
`calendarId` in path parameter
Credential store
`GOOGLE_CONFLICT_THRESHOLD`
Workflow decision node
`conflict_flag` boolean (true if overlapping event count >= threshold)
Agent 2 handoff: Agent 1 output to Slack approval message
Source tool
Source field
Destination tool
Destination field
Leave request form
`employee_name`
Slack Block Kit
`section.text` (display label)
Leave request form
`leave_type`
Slack Block Kit
`section.text` (display label)
Leave request form
`start_date`
Slack Block Kit
`section.text` (display label)
Leave request form
`end_date`
Slack Block Kit
`section.text` (display label)
BambooHR API response
`balance`
Slack Block Kit
`section.text` (remaining balance display)
Workflow context
`conflict_flag`
Slack Block Kit
`section.text` (conflict warning if true)
Workflow context
`request_id`
Slack Block Kit
`actions[].value` (button payload for correlation)
Slack lookupByEmail
`user.id` (manager)
Slack chat.postMessage
`channel` parameter
Agent 2 handoff: Slack interaction callback to Agent 2 routing and Gmail decline branch
Source tool
Source field
Destination tool
Destination field
Slack interaction payload
`actions[0].action_id`
Workflow router
`decision` (approve or decline)
Slack interaction payload
`actions[0].value`
Workflow router
`request_id` (correlation key)
Slack interaction payload
`user.id`
Audit log
`approved_by_slack_id`
Slack interaction payload
`user.name`
Audit log
`approved_by_name`
Leave request form
`employee_email`
Gmail API
`To` header in RFC 2822 message
Leave request form + workflow
`decline_reason`
Gmail template
`{{decline_reason}}` placeholder
Agent 3 handoff: Approved decision to BambooHR, Google Calendar, Gusto, and Slack
Source tool
Source field
Destination tool
Destination field
Leave request form
`employee_id`
BambooHR API
`{employee_id}` in time-off request path
Leave request form
`leave_type`
BambooHR API
`timeOffTypeId` (from BAMBOOHR_LEAVE_TYPE map)
Leave request form
`start_date`
BambooHR API
`start`
Leave request form
`end_date`
BambooHR API
`end`
Leave request form
`days_count`
BambooHR API
`amount`
Leave request form
`employee_name`
Google Calendar API
`summary` (via GOOGLE_EVENT_SUMMARY_TEMPLATE)
Leave request form
`leave_type`
Google Calendar API
`summary` (appended to template)
Leave request form
`start_date`
Google Calendar API
`start.date`
Leave request form
`end_date`
Google Calendar API
`end.date`
Leave request form
`employee_email`
Gusto API
`users.lookupByEmail` -> `employee.uuid`
Leave request form
`leave_type`
Gusto API
`time_off_type_uuid` (from GUSTO_LEAVE_TYPE_MAP)
Leave request form
`start_date`
Gusto API
`start_date`
Leave request form
`end_date`
Gusto API
`end_date`
Leave request form
`days_count`
Gusto API
`days_count`
Slack lookupByEmail
`user.id` (employee)
Slack chat.postMessage
`channel` (employee DM)
Credential store
`SLACK_TEAM_CHANNEL_ID`
Slack chat.postMessage
`channel` (team absence channel)
Integration and API SpecPage 2 of 4
FS-DOC-05Technical
04Build stack and orchestration
Orchestration layout
Three discrete workflows, one per agent. Each workflow is independently deployable and independently restartable. Shared state between agents is passed via a lightweight internal data store or message queue record keyed on request_id. A shared credential store is referenced by all three workflows; no credentials are stored inside individual workflow steps.
Agent 1 trigger
Webhook trigger. The leave request form posts a structured JSON payload to a unique inbound webhook URL on submission. The orchestration layer receives the payload, validates required fields (employee_id, leave_type, start_date, end_date), and begins the Agent 1 workflow. No polling is required.
Agent 2 trigger
Internal message / queue trigger. Agent 1 writes its validated output (request summary, balance status, conflict flag) to an internal queue record tagged with request_id. Agent 2 listens for new records on this queue and begins processing immediately. Agent 2 also registers an inbound webhook URL for Slack interactivity callbacks; this endpoint must validate the X-Slack-Signature header using HMAC-SHA256 with SLACK_SIGNING_SECRET before any payload is processed.
Agent 3 trigger
Internal message / queue trigger. Agent 2 writes the approved decision (decision = approve, request_id, approved_by_slack_id, approved_by_name, approval_timestamp) to the internal queue. Agent 3 picks up approved-only records. Declined records are routed to the Gmail decline step within Agent 2 and do not trigger Agent 3.
Credential store type
Platform-native encrypted secret store. All secrets are referenced by variable name in workflow steps. Secrets are never logged, never included in error payloads, and never passed as query string parameters. Access to the credential store is restricted to the automation platform service account.
Slack signature validation
Every Slack interactivity callback is validated before processing: concatenate 'v0:', the X-Slack-Request-Timestamp header, and the raw request body; compute HMAC-SHA256 using SLACK_SIGNING_SECRET; compare to X-Slack-Signature header value. Reject if mismatch or if timestamp is more than 300 seconds old.
Audit logging
Each workflow step writes a structured log entry (request_id, step_name, tool, status, timestamp) to an append-only internal log. The log is queryable by request_id and is the audit trail for manager approval identity and timing.
Credential store contents (all variables required before any workflow is activated):
All values are populated from the credential store at runtime. No plaintext secrets appear in workflow step definitions or version control.
// BambooHR
BAMBOOHR_API_KEY = "<hr-admin-api-key>"
BAMBOOHR_SUBDOMAIN = "<yourcompany>"
BAMBOOHR_LEAVE_TYPE_ANNUAL = "<numeric-leave-type-id>"
BAMBOOHR_LEAVE_TYPE_SICK = "<numeric-leave-type-id>"
BAMBOOHR_LEAVE_TYPE_UNPAID = "<numeric-leave-type-id>"
BAMBOOHR_LEAVE_TYPE_PARENTAL = "<numeric-leave-type-id>"
// Google Calendar and Gmail (shared service account)
GOOGLE_SERVICE_ACCOUNT_JSON = "<base64-encoded-service-account-key-json>"
GOOGLE_TEAM_CALENDAR_ID = "<team-absence-calendar-id@group.calendar.google.com>"
GOOGLE_CONFLICT_THRESHOLD = 2
GOOGLE_EVENT_SUMMARY_TEMPLATE = "{employee_name} - {leave_type}"
GMAIL_SENDER_ADDRESS = "hr-notifications@yourcompany.com"
GMAIL_DECLINE_TEMPLATE_ID = "<template-ref-or-html-key>"
// Slack
SLACK_BOT_TOKEN = "xoxb-<token>"
SLACK_SIGNING_SECRET = "<slack-app-signing-secret>"
SLACK_TEAM_CHANNEL_ID = "<C0XXXXXXXXX>"
SLACK_APPROVAL_CHANNEL_PREFIX = "leave-approval"
SLACK_INTERACTIVITY_WEBHOOK_URL = "https://automation.yourcompany.com/webhooks/slack-interactions"
// Gusto
GUSTO_CLIENT_ID = "<oauth-client-id>"
GUSTO_CLIENT_SECRET = "<oauth-client-secret>"
GUSTO_REFRESH_TOKEN = "<oauth-refresh-token>"
GUSTO_COMPANY_UUID = "<gusto-company-uuid>"
GUSTO_LEAVE_TYPE_MAP = '{"annual":"<gusto-policy-uuid>","sick":"<gusto-policy-uuid>","unpaid":"<gusto-policy-uuid>","parental":"<gusto-policy-uuid>"}'
// Internal
INTERNAL_QUEUE_DSN = "<queue-connection-string>"
AUDIT_LOG_DSN = "<log-store-connection-string>"Gusto access tokens expire after 2 hours. The orchestration layer must implement an automatic token refresh step before every Gusto API call using GUSTO_CLIENT_ID, GUSTO_CLIENT_SECRET, and GUSTO_REFRESH_TOKEN. Store the refreshed access token in memory for the duration of the workflow run only, never persist it to the credential store.
Integration and API SpecPage 3 of 4
FS-DOC-05Technical
05Error handling and retry logic
Every integration point has a defined failure behaviour. Unhandled exceptions must never fail silently. Every failure must produce a structured log entry with request_id, tool, endpoint, HTTP status or exception type, and timestamp. Critical failures that block record updates must also trigger an alert to the HR admin via Slack DM or email.
Integration
Scenario
Required behaviour
Leave request form inbound webhook
Malformed payload or missing required fields
Reject immediately with HTTP 400. Log the raw payload and field validation errors. Send an automated Gmail reply to employee_email (if parseable) asking them to resubmit. Do not proceed to Agent 1.
BambooHR - balance read (Agent 1)
HTTP 401 or 403 (auth failure)
Halt workflow. Log error with request_id. Alert HR admin via Slack DM: 'BambooHR credential failure - review API key'. Do not retry automatically; requires manual credential refresh.
BambooHR - balance read (Agent 1)
HTTP 429 or 503 (rate limit or service unavailable)
Retry up to 3 times with exponential backoff: 30s, 90s, 270s. If all retries fail, halt workflow and alert HR admin. Log all retry attempts with timestamps.
Google Calendar - conflict check (Agent 1)
HTTP 403 (insufficient permissions or calendar not shared)
Halt workflow. Log error. Alert HR admin: 'Google Calendar access error - verify service account calendar sharing'. Do not proceed to approval routing without a definitive conflict check result.
Google Calendar - conflict check (Agent 1)
HTTP 503 or timeout
Retry up to 3 times with exponential backoff: 15s, 45s, 135s. If all retries fail, set conflict_flag = true (conservative default) and proceed to approval with a warning note in the Slack message indicating the calendar check could not be completed.
Slack - approval message send (Agent 2)
HTTP 404 on manager channel (manager not in workspace)
Halt approval step. Log error with request_id and manager_email. Send Gmail notification to HR admin with request details so manual approval routing can be initiated. Do not leave the request unrouted.
Slack - interactivity callback (Agent 2)
HMAC-SHA256 signature validation fails
Reject payload immediately with HTTP 403. Log the raw request headers (excluding token values) and the failure reason. Do not process any action from an unverified payload.
Slack - interactivity callback (Agent 2)
Interaction payload arrives after 30-minute button expiry
Detect stale timestamp. Respond to Slack with an ephemeral message to the manager: 'This approval request has expired. Please contact HR to reopen.' Log the stale event. Alert HR admin so they can manually re-send the approval request.
BambooHR - leave balance deduction (Agent 3)
HTTP 409 (conflict: balance already modified) or HTTP 422 (insufficient balance at write time)
Do not proceed to Gusto or Google Calendar writes. Log the error with request_id. Alert HR admin via Slack DM with full request context. The manager's approval decision remains in the audit log; HR must manually reconcile.
Google Calendar - event creation (Agent 3)
HTTP 403 or 503
Retry up to 3 times with exponential backoff: 15s, 45s, 135s. If all retries fail, continue with Gusto write and Slack notifications (do not block the employee on a calendar failure), but log the failure and add a task to the HR admin Slack alert to create the event manually.
Gusto - time-off entry write (Agent 3)
HTTP 401 (token expired)
Attempt automatic token refresh using GUSTO_REFRESH_TOKEN. Retry the original request once with the new access token. If refresh fails, log the error, skip the Gusto write, and alert HR admin: 'Gusto write skipped - manual payroll entry required for request {request_id}'.
Gusto - time-off entry write (Agent 3)
HTTP 422 (invalid policy UUID or date range)
Do not retry. Log the full request body and Gusto error response. Alert HR admin: 'Gusto leave type mapping error - review GUSTO_LEAVE_TYPE_MAP credential'. Manual payroll entry required. Continue Slack notification steps so the employee is not left waiting.
Slack - employee and team notifications (Agent 3)
HTTP 429 (rate limit hit across concurrent runs)
Queue the notification and retry after 60 seconds, up to 5 attempts. Slack Tier 3 rate limits are per method per workspace; space notification calls by at least 1.5 seconds when processing multiple requests in a batch run.
Any integration - unhandled exception
Unexpected error type not matched by any above scenario
Catch all unhandled exceptions at the workflow level. Log the full exception with request_id, step name, tool, and stack trace. Send a Slack DM alert to HR admin. Never allow a workflow run to terminate silently. The employee must receive a follow-up communication if their request cannot be processed automatically.
For questions about this specification or to report an integration issue discovered during build, contact the FullSpec team at support@gofullspec.com. Reference the process name (Leave and Absence Management) and the relevant agent number in your message.
Integration and API SpecPage 4 of 4