FS-DOC-05Technical
Integration and API Spec
Policy Acknowledgement Tracking
[YourCompany.com] · HR Department · Prepared by FullSpec · [Today's Date]
This document provides the complete integration and API reference for the three agents that power the Policy Acknowledgement Tracking automation: the Policy Distribution Agent, the Reminder and Escalation Agent, and the Completion and Archiving Agent. It is written for the FullSpec build team and covers every external tool connection, required OAuth scopes, webhook configuration, field mappings between systems, credential store layout, and failure handling behaviour. Nothing in this document requires action from the HR team. All integration work described here is carried out entirely by FullSpec.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by agents
BambooHR
Employee list source and signed document archive
API key (Basic Auth over HTTPS)
Essentials or higher (API access included)
Agent 1, Agent 3
DocuSign
Envelope creation, signature collection, webhook event source
OAuth 2.0 Authorization Code Grant
Standard plan or higher (webhook / Connect feature required)
Agent 1, Agent 2, Agent 3
Gmail
Day-5 reminder email delivery to employees
OAuth 2.0 (Google Identity Platform)
Google Workspace Business Starter or higher
Agent 2
Slack
Day-10 escalation DMs to employees and line managers
OAuth 2.0 (Slack App with Bot token)
Pro plan or higher (DM to non-members of a channel requires paid plan)
Agent 2
Google Sheets
Cycle tracking log: seeding, status updates, completion report
OAuth 2.0 (Google Identity Platform, service account)
Google Workspace Business Starter or higher
Agent 1, Agent 2, Agent 3
Orchestration layer (automation platform)
Workflow scheduling, webhook ingestion, credential store, retry logic
Internal (platform-managed)
Platform plan that supports webhook listeners and scheduled triggers
All agents
Before you connect anything: every integration must be validated in a sandbox or test environment before production credentials are entered. For BambooHR, use a sub-domain test account or a staging API key. For DocuSign, use the DocuSign developer sandbox (demo.docusign.net). For Google services, use a dedicated service account scoped to a non-production Google Workspace. For Slack, deploy the app to a private test workspace first. Only after end-to-end sandbox validation should production credentials be loaded into the credential store.
02Per-tool integration detail
BambooHR
Used by Agent 1 (Policy Distribution Agent) to fetch the active employee list and by Agent 3 (Completion and Archiving Agent) to attach signed PDFs to employee document folders. Authentication uses a per-subdomain API key issued from the BambooHR admin console.
Auth method
HTTP Basic Auth: username = API key, password = 'x'. Key is issued per BambooHR subdomain under Account Settings > API Keys. Store as BAMBOOHR_API_KEY and BAMBOOHR_SUBDOMAIN in the credential store. Never hardcode.
Required scopes
BambooHR API keys are not OAuth-scoped; permission is controlled by the admin role assigned to the key owner. The API key must belong to an account with: Employee Read (all fields including employeeId, firstName, lastName, workEmail, department, supervisorId, status), and Document Write (to upload files to the Files tab of an employee record). Confirm these are available under the assigned role in Settings > Access Levels before build.
Webhook / trigger setup
BambooHR does not natively push a webhook when a policy document is marked active. Agent 1 uses a scheduled poll (every 15 minutes or at a fixed time defined by the policy cycle trigger) to query the employee list endpoint. Alternatively, the HR Manager manually triggers the workflow via the orchestration layer's UI trigger, passing the policy name and version. Both modes must be supported.
Required configuration
BAMBOOHR_SUBDOMAIN stored in credential store. Target employee group filter field (e.g. department name or custom field 'policyGroup') agreed and documented before build. Employee status filter must exclude status = 'Inactive' and status = 'Terminated'. supervisorId field must be populated for all in-scope employees before go-live (data cleanse required if reporting lines are inconsistent).
Key endpoints
GET /v1/employees/directory (list all active employees, apply ?fields=id,firstName,lastName,workEmail,department,supervisorId,status). POST /v1/employees/{id}/files (upload signed PDF; Content-Type: application/pdf; include file name as policy-name_version_employeeId.pdf).
Rate limits
BambooHR enforces a rate limit of approximately 1,000 requests per hour per API key. At 20 to 150 employees per cycle and 3 to 6 cycles per year, peak load is well under 200 requests per cycle run. No throttling is required at current volume; however, the document upload loop for Agent 3 must include a 200ms inter-request delay as a precaution.
Constraints
File uploads via the Files API are limited to 20 MB per file. Signed DocuSign PDFs are typically under 2 MB. The API does not support bulk file upload; each employee record requires a separate POST request. Error responses use non-standard HTTP codes in some versions; treat any 4xx as a hard failure requiring immediate alert.
// Input to BambooHR (Agent 1)
GET /v1/employees/directory?fields=id,firstName,lastName,workEmail,department,supervisorId,status
Headers: { Authorization: 'Basic <base64(BAMBOOHR_API_KEY:x)>', Accept: 'application/json' }
// Output from BambooHR (Agent 1)
{ employees: [ { id, firstName, lastName, workEmail, department, supervisorId, status } ] }
// Input to BambooHR (Agent 3 - document upload)
POST /v1/employees/{employeeId}/files
Headers: { Authorization: 'Basic <base64(BAMBOOHR_API_KEY:x)>', Content-Type: 'multipart/form-data' }
Body: { file: <signed_pdf_binary>, fileName: '<policyName>_<version>_<employeeId>.pdf', category: 'Policy Acknowledgements' }DocuSign
Central to all three agents. Agent 1 creates and sends bulk envelopes from a pre-approved template. Agent 2 polls envelope status for pending signers. Agent 3 listens for the envelope-completed webhook event and retrieves the signed PDF. All DocuSign calls target the eSignature REST API v2.1.
Auth method
OAuth 2.0 Authorization Code Grant for initial authorisation. Long-lived access uses JWT Grant (Service Integration) with an RSA key pair so the orchestration layer can authenticate without user interaction. Store as DOCUSIGN_INTEGRATION_KEY, DOCUSIGN_ACCOUNT_ID, DOCUSIGN_USER_ID, and DOCUSIGN_PRIVATE_KEY_PEM in the credential store.
Required scopes
signature, impersonation, click.manage (if click-wrap is used). For JWT Grant the impersonation scope is mandatory. Scopes are requested at the point the admin consents via the DocuSign OAuth consent URL: https://account.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id={DOCUSIGN_INTEGRATION_KEY}&redirect_uri={REDIRECT_URI}
Webhook / trigger setup
DocuSign Connect must be enabled on the account (Standard plan and above). Configure a Connect listener pointing to the orchestration layer's inbound webhook URL. Subscribe to envelope events: envelope-completed, envelope-declined, envelope-voided. Enable HMAC signature validation: store the HMAC secret as DOCUSIGN_CONNECT_HMAC_SECRET. On every inbound Connect event, the orchestration layer must verify the X-DocuSign-Signature-1 header before processing. Reject and log any request where validation fails.
Required configuration
Pre-approved envelope template ID stored as DOCUSIGN_TEMPLATE_ID (not hardcoded). Template must contain: a {{recipientName}} placeholder in the greeting, a designated SignHere tab, and the policy document as a locked attachment. Template must be version-locked by a DocuSign admin before the build starts. DOCUSIGN_ACCOUNT_ID stored in the credential store. Base URL for sandbox: https://demo.docusign.net/restapi; for production: https://na4.docusign.net/restapi (confirm account region with HR admin).
Key endpoints
POST /v2.1/accounts/{accountId}/envelopes (create and send envelope from template, set signers list). GET /v2.1/accounts/{accountId}/envelopes?status=sent&from_date={iso8601} (poll pending envelopes for Agent 2). GET /v2.1/accounts/{accountId}/envelopes/{envelopeId}/documents/{documentId} (retrieve signed PDF for Agent 3).
Rate limits
DocuSign eSignature API allows 1,000 calls per hour for Standard plan accounts. Bulk send for 150 employees generates approximately 150 API calls per cycle. Daily polling by Agent 2 generates at most 150 calls per run. Total cycle volume is well within limits. No throttling required; implement a 100ms delay between envelope creation calls in the bulk send loop to avoid burst rejection.
Constraints
Bulk send via template requires recipients to be added individually in the envelope creation payload; the Bulk Send V2 endpoint may be used for groups over 50 to reduce call count. The signed PDF retrieval endpoint returns the combined document; if the envelope contains multiple documents, specify documentId = 'combined' to get the merged PDF. Voided or declined envelopes must be caught by the Connect webhook and logged as exceptions in the tracking sheet; they must not be retried automatically without HR review.
// Input to DocuSign (Agent 1 - create envelope)
POST /v2.1/accounts/{DOCUSIGN_ACCOUNT_ID}/envelopes
Body: {
templateId: DOCUSIGN_TEMPLATE_ID,
status: 'sent',
templateRoles: [
{ email: employee.workEmail, name: employee.fullName, roleName: 'Signer',
tabs: { textTabs: [{ tabLabel: 'recipientName', value: employee.firstName }] } }
]
}
// Output from DocuSign Connect webhook (Agent 3 inbound)
{
event: 'envelope-completed',
envelopeId: '<uuid>',
status: 'completed',
completedDateTime: '<iso8601>',
recipients: { signers: [{ email, name, signedDateTime }] }
}Gmail
Used exclusively by Agent 2 (Reminder and Escalation Agent) to send day-5 reminder emails to employees who have not yet signed their DocuSign envelope. Emails are sent from the HR Manager's authorised Google Workspace account using the Gmail API.
Auth method
OAuth 2.0 Authorization Code Grant scoped to the HR Manager's Google account, or a service account with domain-wide delegation if the orchestration layer needs to send on behalf of multiple HR users. Store refresh token as GMAIL_OAUTH_REFRESH_TOKEN and client credentials as GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET.
Required scopes
https://www.googleapis.com/auth/gmail.send (send-only; do not request broader gmail.readonly or gmail.modify unless needed for another use case). If using service account with domain-wide delegation, grant the scope in Google Workspace Admin > Security > API Controls > Domain-wide Delegation.
Webhook / trigger setup
Gmail is an outbound-only integration in this automation. No inbound webhook is required. Agent 2 triggers Gmail sends on a schedule (daily poll at a configured time, e.g. 09:00 in the HR team's local timezone). Timezone must be stored as a configuration variable REMINDER_SEND_TIMEZONE, not hardcoded.
Required configuration
Reminder email HTML template stored as a versioned string in the credential or config store (key: GMAIL_REMINDER_TEMPLATE_HTML). Template must include placeholders: {{employeeFirstName}}, {{policyName}}, {{policyVersion}}, {{docusignEnvelopeUrl}}, {{cycleDeadlineDate}}. From address stored as GMAIL_FROM_ADDRESS. Reply-to address stored as GMAIL_REPLYTO_ADDRESS (typically the HR Manager's address).
Rate limits
Gmail API allows 250 quota units per user per second and a daily send limit of 2,000 messages per Google Workspace account. At a maximum of 150 employees per cycle this is well within limits. No throttling required. Implement exponential backoff on 429 responses as a precaution.
Constraints
Emails must be sent as RFC 2822 formatted messages, base64url-encoded, passed to the messages.send endpoint. Attachments are not required for the reminder email (only the DocuSign link is sent). If the employee's workEmail is a distribution list alias rather than a personal address, the DocuSign envelope link will still route correctly but the reminder may not reach the individual; flag this risk in handover notes.
// Input to Gmail API (Agent 2)
POST https://gmail.googleapis.com/gmail/v1/users/me/messages/send
Headers: { Authorization: 'Bearer <access_token>', Content-Type: 'application/json' }
Body: {
raw: base64url(
'From: GMAIL_FROM_ADDRESS\r\n' +
'Reply-To: GMAIL_REPLYTO_ADDRESS\r\n' +
'To: employee.workEmail\r\n' +
'Subject: Reminder: Please sign the [policyName] acknowledgement\r\n' +
'Content-Type: text/html; charset=utf-8\r\n\r\n' +
GMAIL_REMINDER_TEMPLATE_HTML (with placeholders resolved)
)
}Slack
Used by Agent 2 (Reminder and Escalation Agent) on day 10 to send direct messages to non-signing employees and separate DMs to their line managers. Operates via a dedicated Slack App installed in the organisation's workspace with a bot token.
Auth method
OAuth 2.0 Slack App installation flow. The resulting bot token (xoxb-...) is stored as SLACK_BOT_TOKEN in the credential store. A separate user token is not required. The Slack App must be installed by a Slack workspace admin.
Required scopes
chat:write (send messages as the bot), im:write (open DM channels with users), users:read (look up Slack user ID by email address), users:read.email (required to resolve email to Slack user ID). Add these scopes under the Slack App's OAuth and Permissions page before installation.
Webhook / trigger setup
Slack is outbound-only in this automation. No incoming webhook or event subscription is required. Agent 2 calls the Slack API on its daily schedule when day-10 conditions are met. Slack user IDs are resolved at runtime by calling users.lookupByEmail with the employee's workEmail. Cache resolved Slack user IDs in the tracking sheet (column: slack_user_id) to avoid repeated lookups.
Required configuration
SLACK_BOT_TOKEN stored in credential store. Escalation message templates stored as config variables: SLACK_EMPLOYEE_MSG_TEMPLATE and SLACK_MANAGER_MSG_TEMPLATE, with placeholders {{employeeFirstName}}, {{policyName}}, {{cycleDeadlineDate}}, {{docusignEnvelopeUrl}}. SLACK_ESCALATION_CHANNEL (optional: a fallback HR channel for cases where the manager's Slack ID cannot be resolved) stored in config.
Rate limits
Slack API Tier 3 methods (chat.postMessage) allow approximately 50 calls per minute. At 150 employees maximum per cycle, Agent 2 may send up to 300 messages (one per employee, one per manager) in a single escalation run. At a conservative 2 messages per second this completes in under 3 minutes and stays within rate limits. Implement a 500ms delay between postMessage calls and handle 429 responses with retry-after header respect.
Constraints
users.lookupByEmail requires the users:read.email scope and will fail if the employee's Slack account email does not match their BambooHR workEmail. Implement a fallback: if the Slack user ID cannot be resolved, post the escalation message to SLACK_ESCALATION_CHANNEL with the employee name, and log the mismatch. The bot must be invited to any private channel used for escalations before it can post there.
// Step 1: Resolve Slack user ID by email (Agent 2)
GET https://slack.com/api/users.lookupByEmail?email={employee.workEmail}
Headers: { Authorization: 'Bearer SLACK_BOT_TOKEN' }
Response: { ok: true, user: { id: 'U012AB3CD', profile: { real_name, email } } }
// Step 2: Send DM to employee (Agent 2)
POST https://slack.com/api/chat.postMessage
Body: {
channel: employee.slackUserId,
text: SLACK_EMPLOYEE_MSG_TEMPLATE (resolved)
}
// Step 3: Send DM to line manager (Agent 2)
POST https://slack.com/api/chat.postMessage
Body: {
channel: manager.slackUserId,
text: SLACK_MANAGER_MSG_TEMPLATE (resolved)
}Integration and API SpecPage 1 of 4
FS-DOC-05Technical
Google Sheets
Used by all three agents as the central cycle tracking log. Agent 1 seeds the sheet at the start of each cycle. Agent 2 reads it to determine reminder and escalation targets and writes status updates. Agent 3 marks rows as signed with timestamps and generates the completion report tab.
Auth method
OAuth 2.0 using a Google service account with the Sheets API enabled in the Google Cloud project. The service account JSON key file contents are stored as GOOGLE_SERVICE_ACCOUNT_JSON in the credential store. The service account email must be granted Editor access on the master tracking spreadsheet.
Required scopes
https://www.googleapis.com/auth/spreadsheets (full read/write access to spreadsheet data). Do not use the drive scope unless the orchestration layer also needs to create new spreadsheet files programmatically; in that case also add https://www.googleapis.com/auth/drive.file (scoped to files created by the app).
Webhook / trigger setup
Google Sheets does not support outbound webhooks natively. All reads and writes are performed by the agents on their scheduled runs or in response to DocuSign webhook events. The master spreadsheet ID is stored as GSHEETS_TRACKING_SPREADSHEET_ID in the credential store.
Required configuration
GSHEETS_TRACKING_SPREADSHEET_ID stored in credential store. Tab naming convention for each cycle: 'Cycle_{policyName}_{YYYY-MM-DD}' (created programmatically by Agent 1). Column structure must match the field mapping exactly (see Section 03). The completion report is written to a tab named 'Report_{policyName}_{YYYY-MM-DD}'. Sheet headers must be present in row 1 as defined in the field mapping table; the automation uses column index references, not named ranges, for performance.
Rate limits
Google Sheets API allows 300 read requests per minute per project and 300 write requests per minute per project. At 150 employees per cycle, a full seeding operation generates approximately 1 batchUpdate call (using values.batchUpdate to write all rows at once). Agent 2 reads the full sheet in a single values.get call. No throttling is required at current volume. Use batchUpdate for all writes rather than individual cell updates.
Constraints
All writes must use values.batchUpdate with valueInputOption: 'USER_ENTERED' to ensure date values are interpreted as dates rather than strings. Row appends must use append with insertDataOption: 'INSERT_ROWS' to avoid overwriting existing data. The orchestration layer must handle the case where the tab for a cycle already exists (e.g. if Agent 1 is re-triggered); implement an idempotency check by tab name before creating a new tab.
// Agent 1: Seed cycle tracking tab
POST https://sheets.googleapis.com/v4/spreadsheets/{GSHEETS_TRACKING_SPREADSHEET_ID}/values/{tabName}!A1:K1:append
Body: { values: [['employeeId','firstName','lastName','workEmail','department','supervisorId',
'envelopeId','status','sentDate','signedDate','escalationDate']], valueInputOption: 'USER_ENTERED' }
// Agent 2: Read pending rows
GET https://sheets.googleapis.com/v4/spreadsheets/{GSHEETS_TRACKING_SPREADSHEET_ID}/values/{tabName}!A:K
// Agent 3: Update row on signature
POST https://sheets.googleapis.com/v4/spreadsheets/{GSHEETS_TRACKING_SPREADSHEET_ID}/values:batchUpdate
Body: { valueInputOption: 'USER_ENTERED', data: [{ range: '{tabName}!H{rowIndex}:J{rowIndex}',
values: [['Signed', completedDateTime, '']] }] }03Field mappings between tools
The following tables define the exact field mappings for each agent handoff. Source and destination field names are shown in monospace format as they appear in the respective API responses and request payloads.
Agent 1 handoff: BambooHR to Google Sheets (cycle seeding)
Source tool
Source field
Destination tool
Destination field
BambooHR
`employees[].id`
Google Sheets
`employeeId` (col A)
BambooHR
`employees[].firstName`
Google Sheets
`firstName` (col B)
BambooHR
`employees[].lastName`
Google Sheets
`lastName` (col C)
BambooHR
`employees[].workEmail`
Google Sheets
`workEmail` (col D)
BambooHR
`employees[].department`
Google Sheets
`department` (col E)
BambooHR
`employees[].supervisorId`
Google Sheets
`supervisorId` (col F)
Orchestration layer (runtime)
`'Pending'` (literal)
Google Sheets
`status` (col H)
Orchestration layer (runtime)
`new Date().toISOString()`
Google Sheets
`sentDate` (col I)
Agent 1 handoff: BambooHR plus Google Sheets to DocuSign (envelope creation)
Source tool
Source field
Destination tool
Destination field
BambooHR
`employees[].workEmail`
DocuSign
`templateRoles[].email`
BambooHR
`employees[].firstName + ' ' + lastName`
DocuSign
`templateRoles[].name`
BambooHR
`employees[].firstName`
DocuSign
`templateRoles[].tabs.textTabs[tabLabel='recipientName'].value`
Config store
`DOCUSIGN_TEMPLATE_ID`
DocuSign
`templateId`
Google Sheets
`envelopeId` (col G, written back after creation)
DocuSign
n/a (stored for later poll and webhook matching)
Agent 2 handoff: Google Sheets to Gmail (day-5 reminder)
Source tool
Source field
Destination tool
Destination field
Google Sheets
`workEmail` (col D)
Gmail
`To:` header
Google Sheets
`firstName` (col B)
Gmail
`{{employeeFirstName}}` placeholder in GMAIL_REMINDER_TEMPLATE_HTML
Config store
`POLICY_NAME`
Gmail
`{{policyName}}` placeholder
Config store
`POLICY_VERSION`
Gmail
`{{policyVersion}}` placeholder
Config store
`CYCLE_DEADLINE_DATE`
Gmail
`{{cycleDeadlineDate}}` placeholder
DocuSign (stored in Sheets col G)
`envelopeId`
Gmail
`{{docusignEnvelopeUrl}}` (constructed as: https://app.docusign.com/sign?envelopeId={envelopeId})
Agent 2 handoff: Google Sheets to Slack (day-10 escalation)
Source tool
Source field
Destination tool
Destination field
Google Sheets
`workEmail` (col D)
Slack
`users.lookupByEmail?email=` query parameter
Google Sheets
`firstName` (col B)
Slack
`{{employeeFirstName}}` in SLACK_EMPLOYEE_MSG_TEMPLATE
Google Sheets
`supervisorId` (col F)
Slack
Used to fetch supervisor workEmail from BambooHR, then resolve to Slack user ID
BambooHR (secondary lookup)
`employees[supervisorId].workEmail`
Slack
`users.lookupByEmail?email=` for manager DM
Config store
`POLICY_NAME`, `CYCLE_DEADLINE_DATE`
Slack
`{{policyName}}`, `{{cycleDeadlineDate}}` in both message templates
Agent 3 handoff: DocuSign webhook to BambooHR and Google Sheets (completion archiving)
Source tool
Source field
Destination tool
Destination field
DocuSign Connect webhook
`envelopeId`
Google Sheets
Matched against `envelopeId` (col G) to identify the correct row
DocuSign Connect webhook
`recipients.signers[0].signedDateTime`
Google Sheets
`signedDate` (col J)
DocuSign Connect webhook
`status` ('completed')
Google Sheets
`status` (col H, written as 'Signed')
DocuSign (document retrieval)
Signed PDF binary from GET /envelopes/{envelopeId}/documents/combined
BambooHR
POST /employees/{employeeId}/files (body: pdf binary)
Google Sheets
`employeeId` (col A)
BambooHR
`{employeeId}` in POST URL path
Config store
`POLICY_NAME`, `POLICY_VERSION`
BambooHR
`fileName` constructed as `{POLICY_NAME}_{POLICY_VERSION}_{employeeId}.pdf`
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, versioned, and restartable. Shared credential store is referenced by all three workflows; no credentials are duplicated across workflows. Inter-agent communication occurs via shared Google Sheets state and DocuSign webhook events, not direct API calls between agents.
Agent 1 trigger
Manual trigger (HR Manager initiates via the orchestration layer UI, passing policyName, policyVersion, targetGroup, and cycleDeadlineDate as inputs) OR scheduled poll of BambooHR for a custom field value indicating a new policy cycle. Poll interval: every 15 minutes during business hours (08:00 to 18:00 in REMINDER_SEND_TIMEZONE). Webhook-based trigger from BambooHR is not available natively; use the poll model as primary.
Agent 2 trigger
Time-based schedule. Runs daily at a configured time (default: 09:00 in REMINDER_SEND_TIMEZONE). The workflow reads the current tracking sheet, evaluates day offsets from sentDate (col I), and conditionally executes reminder and escalation branches. No inbound webhook required.
Agent 3 trigger
Inbound webhook from DocuSign Connect. The orchestration layer exposes a public HTTPS endpoint as the Connect listener URL. Every inbound request must be validated using HMAC-SHA256 against the X-DocuSign-Signature-1 header using DOCUSIGN_CONNECT_HMAC_SECRET before any processing begins. Invalid signatures must return HTTP 401 and be logged. The workflow is also triggered on a fallback schedule (daily at 18:00) to catch any Connect events that may have been missed.
Credential store
All secrets and environment-specific configuration are stored in the orchestration platform's built-in encrypted credential store. No secrets appear in workflow code, logs, or version control. See code block below for the full list of required entries.
Idempotency
Agent 1 checks for an existing tracking tab by the cycle name before creating a new one. Agent 3 checks the status column for 'Signed' before processing a DocuSign webhook event to prevent duplicate file uploads on repeated Connect deliveries. Agent 2 records the last reminder date (col K: lastReminderDate) to prevent duplicate sends.
Logging
Each workflow writes a structured log entry (timestamp, workflowName, employeeId, action, result, errorCode) to a dedicated 'AutomationLog' tab in the master tracking spreadsheet. Errors also trigger a Slack alert to SLACK_ESCALATION_CHANNEL. Log retention: 90 days minimum.
Full credential store entries required across all three agents. Sandbox and production entries must be stored separately with distinct names (e.g. BAMBOOHR_API_KEY_PROD, BAMBOOHR_API_KEY_SANDBOX).
// Credential store entries (orchestration platform secret manager)
// All values are environment-specific; production and sandbox use separate entries
// BambooHR
BAMBOOHR_API_KEY = '<api-key-from-bamboohr-admin>'
BAMBOOHR_SUBDOMAIN = '<your-subdomain>' // e.g. 'acme' for acme.bamboohr.com
// DocuSign
DOCUSIGN_INTEGRATION_KEY = '<oauth-app-client-id>'
DOCUSIGN_ACCOUNT_ID = '<docusign-account-uuid>'
DOCUSIGN_USER_ID = '<docusign-user-uuid-for-jwt-grant>'
DOCUSIGN_PRIVATE_KEY_PEM = '<rsa-private-key-pem-block>'
DOCUSIGN_TEMPLATE_ID = '<envelope-template-uuid>'
DOCUSIGN_CONNECT_HMAC_SECRET = '<hmac-secret-from-connect-config>'
DOCUSIGN_BASE_URL = 'https://na4.docusign.net/restapi' // update per account region
// Google (shared for Gmail and Google Sheets)
GOOGLE_CLIENT_ID = '<google-oauth-client-id>'
GOOGLE_CLIENT_SECRET = '<google-oauth-client-secret>'
GMAIL_OAUTH_REFRESH_TOKEN = '<refresh-token-for-hr-gmail-account>'
GMAIL_FROM_ADDRESS = 'hr@[YourCompany.com]'
GMAIL_REPLYTO_ADDRESS = 'hr-manager@[YourCompany.com]'
GMAIL_REMINDER_TEMPLATE_HTML = '<versioned-html-string-stored-here>'
GOOGLE_SERVICE_ACCOUNT_JSON = '<service-account-key-json-as-string>'
GSHEETS_TRACKING_SPREADSHEET_ID = '<google-sheets-file-id>'
// Slack
SLACK_BOT_TOKEN = 'xoxb-<slack-bot-token>'
SLACK_EMPLOYEE_MSG_TEMPLATE = '<versioned-message-string>'
SLACK_MANAGER_MSG_TEMPLATE = '<versioned-message-string>'
SLACK_ESCALATION_CHANNEL = 'C0123456789' // channel ID, not name
// Cycle-level configuration (set per run, not shared secrets)
POLICY_NAME = '<set at workflow trigger time>'
POLICY_VERSION = '<set at workflow trigger time>'
CYCLE_DEADLINE_DATE = '<ISO 8601 date set at trigger time>'
REMINDER_SEND_TIMEZONE = 'America/New_York' // update to HR team timezone
REMINDER_DAY_5_OFFSET = 5
REMINDER_DAY_10_OFFSET = 10
05Error handling and retry logic
Unhandled exceptions must never fail silently. Every integration point must log the error to the AutomationLog tab in Google Sheets and send a Slack alert to SLACK_ESCALATION_CHANNEL with the workflow name, step name, affected employeeId (where applicable), error code, and timestamp. A workflow that cannot log to Sheets due to a Sheets API failure must fall back to logging via Slack only.
Integration
Scenario
Required behaviour
BambooHR / Employee list fetch
API returns 401 Unauthorized
Halt workflow immediately. Do not proceed to envelope creation. Alert SLACK_ESCALATION_CHANNEL with error. Log to AutomationLog. No retry (credential failure requires human intervention to rotate key).
BambooHR / Employee list fetch
API returns 429 or 503
Retry with exponential backoff: wait 10s, 30s, 90s (3 attempts). If all fail, halt and alert. Log each attempt.
DocuSign / Envelope creation (bulk send loop)
Single envelope creation returns 400 Bad Request (e.g. invalid email)
Skip that employee record, mark status as 'EnvelopeError' in Google Sheets (col H), log the error with employeeId and API response body, continue with remaining employees. Alert HR via SLACK_ESCALATION_CHANNEL listing all failed recipients at end of run.
DocuSign / Envelope creation
API returns 401 (JWT token expired or revoked)
Attempt token refresh once via JWT Grant. If refresh fails, halt workflow and alert. Log token refresh failure. Do not retry envelope creation until fresh token is confirmed.
DocuSign Connect / Inbound webhook
HMAC signature validation fails
Return HTTP 401 immediately. Log the raw request headers and source IP to AutomationLog. Do not process the payload. Alert SLACK_ESCALATION_CHANNEL if more than 3 validation failures occur within 10 minutes (potential spoofing attempt).
DocuSign Connect / Inbound webhook
Orchestration layer endpoint is temporarily unavailable and Connect retries
DocuSign Connect retries failed deliveries up to 5 times over 24 hours. The orchestration layer must implement idempotency on envelopeId to prevent duplicate processing on retry delivery. Log each received event with envelopeId and processing result.
Gmail / Reminder send
API returns 429 (rate limit exceeded)
Respect Retry-After header if present. Otherwise wait 60 seconds and retry up to 3 times. If all retries fail, mark the employee row in Google Sheets with status 'ReminderFailed' and log. Do not block the rest of the reminder batch.
Gmail / Reminder send
Recipient email address bounces or is rejected by receiving server
Gmail API returns 200 on send; bounce handling is out of band. Implement a separate check: if the employee's workEmail domain is known to be invalid (detected via BambooHR data quality), flag before sending. Log any SMTP-level bounce notifications received at GMAIL_REPLYTO_ADDRESS for manual review.
Slack / User ID lookup
users.lookupByEmail returns 'users_not_found' (email mismatch between BambooHR and Slack)
Do not halt. Post the escalation message to SLACK_ESCALATION_CHANNEL with the employee name and manager name in plain text so HR can relay manually. Log the mismatch with employeeId and email so the data quality issue can be corrected.
Slack / DM send
API returns 'channel_not_found' or 'not_in_channel'
Retry once after opening the DM channel via conversations.open. If still failing, fall back to posting in SLACK_ESCALATION_CHANNEL. Log the failure.
Google Sheets / Write operation
API returns 503 Service Unavailable
Retry with exponential backoff: 5s, 15s, 45s (3 attempts). If all fail, buffer the write payload in the orchestration layer's internal state and reattempt on the next scheduled run. Alert SLACK_ESCALATION_CHANNEL. Do not lose data.
BambooHR / Document upload (Agent 3)
POST returns 400 (file size, format, or category error)
Log the error with employeeId, fileName, and response body. Mark the Google Sheets row with status 'ArchiveError'. Alert SLACK_ESCALATION_CHANNEL. Do not retry automatically; require FullSpec review of the file or endpoint configuration before manual re-trigger.
For any error category not covered by the table above, the default behaviour is: log the full error (timestamp, workflow, step, error code, payload excerpt) to AutomationLog, send a Slack alert to SLACK_ESCALATION_CHANNEL, and halt the affected workflow branch gracefully without affecting other in-progress branches. Contact support@gofullspec.com with the AutomationLog export if an unclassified error persists.
Integration and API SpecPage 3 of 4
FS-DOC-05Technical
Document reference: FS-DOC-05 | Process: Policy Acknowledgement Tracking | Build option: Standard ($2,600 one-off) | Prepared by FullSpec | Contact: support@gofullspec.com
Integration and API SpecPage 4 of 4