FS-DOC-05Technical
Integration and API Spec
Contractor and Freelancer Management
[YourCompany.com] · HR Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for every integration point in the Contractor and Freelancer Management automation. It covers authentication methods, required OAuth scopes, webhook configuration, field mappings between tools, credential-store layout, and error-handling behaviour for both the Contractor Onboarding Agent (Agent 1) and the Invoice Processing Agent (Agent 2). The FullSpec team uses this spec to build and maintain the automation. Your team does not need to action anything in this document directly, but the credential values and API plan confirmations noted below must be in place before the build begins.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by agent(s)
Automation platform (orchestration layer)
Hosts all workflows, credential store, and inter-agent logic
Internal service account / environment secrets
N/A — build-time decision
Agent 1, Agent 2
HubSpot
Contractor CRM record creation, rate storage, approval logging
OAuth 2.0 (private app token)
Sales Hub Starter or above
Agent 1, Agent 2
DocuSign
Contract template dispatch and completion status polling
OAuth 2.0 (JWT Grant)
Business Pro or above
Agent 1
Google Drive
Compliance document storage, folder creation, timestamped filing
OAuth 2.0 (service account)
Google Workspace Business Starter or above
Agent 1
Slack
HR alerts, document chase notifications, invoice approval routing
OAuth 2.0 (Bot Token)
Pro plan or above (for workflow steps)
Agent 1, Agent 2
Xero
Bill creation, expense categorisation, payment scheduling
OAuth 2.0 (PKCE)
Starter plan or above
Agent 2
Gusto
Contractor payee creation and payment run trigger
OAuth 2.0 (authorisation code)
Plus plan or above (API access required)
Agent 1, Agent 2
Before you connect anything: sandbox-test every integration using non-production credentials before any production credentials are stored or used. Each tool listed above offers a sandbox or developer environment. The FullSpec team will validate all connections in sandbox mode, confirm expected payloads, and document any behavioural differences before switching to live credentials.
02Per-tool integration detail
HubSpot
Used by both agents as the system of record for contractor profiles, agreed rates, milestone data, and invoice approval decisions. Agent 1 creates and updates contact records. Agent 2 reads rate data and writes approval outcomes.
Auth method
OAuth 2.0 via HubSpot Private App. Generate a private app token in Settings > Integrations > Private Apps. Token is long-lived but should be rotated every 90 days.
Required scopes
crm.objects.contacts.read, crm.objects.contacts.write, crm.objects.deals.read, crm.objects.deals.write, crm.schemas.contacts.read, crm.schemas.contacts.write, timeline.read, timeline.write, forms.read, oauth
Webhook / trigger setup
Subscribe to the contact.creation and contact.propertyChange webhook events via HubSpot's Webhook API (POST /webhooks/v3/{appId}/subscriptions). Filter on lifecycle_stage = contractor (custom property). Validate the X-HubSpot-Signature-v3 header using HMAC-SHA256 against the app client secret on every inbound request.
Required configuration
Create a custom contact property group named Contractor Details containing: contractor_type (enumeration), agreed_rate_usd (number), payment_frequency (enumeration: weekly, biweekly, monthly), compliance_status (enumeration: pending, complete, flagged), invoice_approval_status (enumeration: pending, approved, queried). Pipeline stage names must match exactly: Engagement Confirmed, Documents Pending, Documents Complete, Agreement Signed, Payee Created, Active. Store the private app token in the credential store as HUBSPOT_API_TOKEN — never hardcode.
Rate limits
100 requests/10 seconds per private app (Burst); 500,000 requests/day. At ~12 contractor engagements/month and ~220 automation runs/month, peak usage is well below burst limits. Throttling is not required at current volume but the orchestration layer must queue concurrent webhook triggers to avoid burst spikes during batch onboarding.
Constraints
Custom properties must be created before the first workflow run. The webhook subscription URL must be HTTPS with a valid certificate. Private app tokens cannot be used with HubSpot sandbox accounts — use a separate sandbox app for testing.
// Input (Agent 1)
POST /crm/v3/objects/contacts
{ firstname, lastname, email, phone, contractor_type, agreed_rate_usd, hs_lifecycle_stage: 'contractor' }
// Input (Agent 2 — read)
GET /crm/v3/objects/contacts/{contactId}?properties=agreed_rate_usd,compliance_status,invoice_approval_status
// Output (Agent 2 — write approval result)
PATCH /crm/v3/objects/contacts/{contactId}
{ invoice_approval_status: 'approved' | 'queried', last_invoice_amount_usd: <number> }DocuSign
Used by Agent 1 to send the correct contractor agreement template, monitor envelope status, and confirm completion. Envelope completion triggers the Gusto payee creation step.
Auth method
OAuth 2.0 JWT Grant. The automation platform acts as a service integration; generate an RSA key pair in the DocuSign developer console, upload the public key, and store the private key as DOCUSIGN_RSA_PRIVATE_KEY in the credential store. The integration key (client ID) is stored as DOCUSIGN_INTEGRATION_KEY.
Required scopes
signature, impersonation (required for JWT Grant service accounts). The impersonating user must be a DocuSign admin who has granted consent at https://account.docusign.com/oauth/auth?response_type=code&scope=signature+impersonation.
Webhook / trigger setup
Create a Connect webhook listener in DocuSign Admin > Connect. Set the trigger event to Envelope Completed and Envelope Declined. The listener URL is the automation platform's inbound HTTPS endpoint. Validate the X-DocuSign-Signature-1 HMAC header using the Connect HMAC key stored as DOCUSIGN_CONNECT_HMAC_KEY.
Required configuration
Templates must be pre-built in DocuSign with role names matching exactly: Contractor (signer), [YourCompany.com] Authorised Signatory (signer). Template IDs must be stored in the credential store by contractor type, e.g. DOCUSIGN_TEMPLATE_ID_STANDARD, DOCUSIGN_TEMPLATE_ID_NDA_ONLY. Pre-fill tab labels used by the automation: contractor_full_name, contractor_email, agreed_rate_usd, engagement_start_date, role_title. The Account ID and Base URI are stored as DOCUSIGN_ACCOUNT_ID and DOCUSIGN_BASE_URI.
Rate limits
DocuSign Business Pro allows 1,000 API calls/hour per integration key. At 12 engagements/month, peak usage is negligible. No throttling needed. Monitor for 429 responses and implement a 60-second back-off if encountered.
Constraints
JWT Grant tokens expire after 1 hour; the orchestration layer must refresh before expiry. Envelopes cannot be edited after sending — if a template change is needed, void and resend. Voided envelope events also fire the Connect webhook and must be handled without triggering a duplicate send.
// Input — send envelope
POST /restapi/v2.1/accounts/{accountId}/envelopes
{ templateId, templateRoles: [{ roleName: 'Contractor', name, email, tabs: { textTabs: [ contractor_full_name, agreed_rate_usd, engagement_start_date ] } }], status: 'sent' }
// Inbound webhook payload (Connect)
{ envelopeId, status: 'completed' | 'declined' | 'voided', completedDateTime, recipientStatuses: [ ... ] }
// Output — envelope ID stored to HubSpot
PATCH /crm/v3/objects/contacts/{contactId} { docusign_envelope_id: <envelopeId> }Google Drive
Used by Agent 1 to create contractor-specific folders, file compliance documents submitted by contractors, and apply a timestamped naming convention for audit purposes.
Auth method
OAuth 2.0 via a Google Cloud service account. Create a service account in Google Cloud Console, download the JSON key file, and store its contents as GOOGLE_SERVICE_ACCOUNT_JSON in the credential store. Share the root Contractors folder in Google Drive with the service account email address (Editor role).
Required scopes
https://www.googleapis.com/auth/drive.file, https://www.googleapis.com/auth/drive.metadata.readonly
Webhook / trigger setup
No inbound webhook required. Agent 1 polls for uploaded documents by checking a designated intake folder (ID stored as GDRIVE_INTAKE_FOLDER_ID) every 15 minutes using the Drive Files: list API filtered by modifiedTime. A push notification channel (Drive API v3 Watch) may be configured as an optional optimisation to reduce polling latency, delivering events to the automation platform's HTTPS endpoint.
Required configuration
Root folder structure must be created before build: /Contractors/{contractor_id}/Compliance/ and /Contractors/{contractor_id}/Agreements/. The root folder ID is stored as GDRIVE_ROOT_FOLDER_ID. File naming convention: {YYYY-MM-DD}_{contractor_id}_{document_type} (e.g. 2024-05-01_CTR-0042_W9.pdf). Document type labels used in automation logic: W9, NDA, BANK_DETAILS, PORTFOLIO, CERTIFICATION. Intake folder ID stored as GDRIVE_INTAKE_FOLDER_ID.
Rate limits
Google Drive API: 12,000 queries/minute per project. At 220 runs/month with 15-minute polling intervals, usage is trivially low. No throttling required.
Constraints
Service account cannot access files unless the containing folder has been explicitly shared with it. Drive API does not support folder-level webhooks natively — use the Watch endpoint per file or rely on polling. Files uploaded directly by contractors via a form must land in the intake folder; the form tool must be configured to write to GDRIVE_INTAKE_FOLDER_ID.
// Input — create contractor subfolder
POST https://www.googleapis.com/drive/v3/files
{ name: '{contractor_id}', mimeType: 'application/vnd.google-apps.folder', parents: [GDRIVE_ROOT_FOLDER_ID] }
// Input — move and rename filed document
PATCH https://www.googleapis.com/drive/v3/files/{fileId}
{ name: '{YYYY-MM-DD}_{contractor_id}_{document_type}', addParents: '{complianceFolderId}', removeParents: '{intakeFolderId}' }
// Output — file metadata stored to HubSpot contact note
{ gdrive_file_id, gdrive_file_url, filed_at_utc, document_type }Integration and API SpecPage 1 of 4
FS-DOC-05Technical
Slack
Used by both agents for internal HR alerts (document chase notifications, onboarding status) and for invoice approval routing with interactive approve/query buttons delivered to the approving manager.
Auth method
OAuth 2.0 Bot Token. Install the Slack app to the workspace via the App Directory or a custom app manifest. Store the Bot User OAuth Token as SLACK_BOT_TOKEN and the Signing Secret as SLACK_SIGNING_SECRET.
Required scopes
chat:write, chat:write.public, channels:read, users:read, users:read.email, im:write, commands (for interactive components), incoming-webhook (optional for simpler alert use cases)
Webhook / trigger setup
Enable Interactivity in the Slack app settings (App > Interactivity and Shortcuts). Set the Request URL to the automation platform's HTTPS inbound endpoint for Slack actions. Validate every inbound interaction payload by verifying the X-Slack-Signature header using HMAC-SHA256 with SLACK_SIGNING_SECRET and the X-Slack-Request-Timestamp value. Reject requests where timestamp is older than 5 minutes.
Required configuration
Slack channel IDs must be stored in the credential store: SLACK_HR_CHANNEL_ID (for HR alerts and document chase notifications), SLACK_FINANCE_CHANNEL_ID (for invoice mismatch alerts). Manager user IDs or email-to-user-ID resolution must be performed at runtime using users.lookupByEmail. Invoice approval messages use Block Kit with two action buttons: action_id: invoice_approve and action_id: invoice_query. The action payload must include contractor_id, invoice_amount_usd, hubspot_contact_id, and xero_draft_bill_id.
Rate limits
Slack Web API: Tier 3 methods (chat.postMessage) allow 1 request/second. At current volume (12 contractor engagements/month, ~220 runs/month) this limit is not approached. Queue messages sequentially if batch notifications are triggered simultaneously.
Constraints
Bot must be invited to every channel it posts to before the first workflow run. Interactive message payloads expire after 30 minutes — if a manager does not act within 30 minutes, the approval request must be re-sent or escalated. Slack does not guarantee message delivery order; log every sent message timestamp in HubSpot.
// Input — HR alert (document chase)
POST https://slack.com/api/chat.postMessage
{ channel: SLACK_HR_CHANNEL_ID, text: 'Reminder: {contractor_name} has not submitted {missing_docs}. Day {n} of chase sequence.' }
// Input — invoice approval Block Kit message
{ channel: '{manager_slack_user_id}', blocks: [ section(contractor_name, invoice_amount_usd, due_date), actions([ { type: 'button', action_id: 'invoice_approve', text: 'Approve' }, { type: 'button', action_id: 'invoice_query', text: 'Query', style: 'danger' } ]) ] }
// Inbound action payload
{ action_id: 'invoice_approve' | 'invoice_query', value: { contractor_id, hubspot_contact_id, invoice_amount_usd, xero_draft_bill_id } }Xero
Used by Agent 2 to create approved contractor bills, assign expense categories, attach the invoice PDF, and schedule the payment run.
Auth method
OAuth 2.0 with PKCE. Register the automation platform as a connected app in Xero Developer Portal. Store the client ID as XERO_CLIENT_ID, the client secret as XERO_CLIENT_SECRET, the access token (short-lived, 30 min) as XERO_ACCESS_TOKEN, and the refresh token (60-day rolling) as XERO_REFRESH_TOKEN. Implement token refresh before every API call using /identity/connect/token.
Required scopes
accounting.transactions, accounting.transactions.read, accounting.contacts, accounting.contacts.read, accounting.attachments, accounting.settings.read, offline_access
Webhook / trigger setup
No inbound webhook required. All interactions are outbound from the automation platform on receipt of a Slack approval action. Optionally subscribe to Xero's webhook for PaymentCreated events to confirm payment scheduling — configure via Xero Developer Portal and validate the x-xero-signature header.
Required configuration
The Xero tenant/organisation ID must be stored as XERO_TENANT_ID. Expense account codes for contractor payments must be agreed with the finance team before build and stored as XERO_CONTRACTOR_ACCOUNT_CODE (e.g. 200 for Contractor Fees). The default payment due date offset (e.g. 14 days from bill date) is stored as XERO_PAYMENT_DUE_DAYS. Contact records for each contractor must exist in Xero before a bill can be raised — the automation creates these via the Contacts API if not found.
Rate limits
Xero API: 60 calls/minute per app, 5,000 calls/day. At 220 runs/month the daily limit is not approached. Implement 429 handling with a 1-minute back-off and retry.
Constraints
Access tokens expire every 30 minutes — always refresh before making calls. Refresh tokens expire after 60 days if unused; implement a scheduled keep-alive ping. Bills cannot be deleted via API once they reach Authorised status — void and reissue if a correction is needed. Attachment upload (invoice PDF) must be a separate API call after bill creation.
// Input — create bill (ACCPAY invoice)
POST https://api.xero.com/api.xro/2.0/Invoices
{ Type: 'ACCPAY', Contact: { ContactID: xero_contact_id }, Date: today_iso, DueDate: today_plus_XERO_PAYMENT_DUE_DAYS, LineItems: [ { Description: invoice_description, Quantity: 1, UnitAmount: invoice_amount_usd, AccountCode: XERO_CONTRACTOR_ACCOUNT_CODE } ], Status: 'AUTHORISED' }
// Input — attach PDF
POST https://api.xero.com/api.xro/2.0/Invoices/{InvoiceID}/Attachments/{filename}
Content-Type: application/pdf | body: <pdf binary>
// Output
{ InvoiceID, InvoiceNumber, Status: 'AUTHORISED', DueDate, AmountDue }Gusto
Used by Agent 1 to create the contractor as a payee after DocuSign completion, and by Agent 2 to optionally trigger a payment run once the Xero bill is authorised.
Auth method
OAuth 2.0 authorisation code flow. Register the automation platform in Gusto Developer Portal. Store the client ID as GUSTO_CLIENT_ID, client secret as GUSTO_CLIENT_SECRET, access token as GUSTO_ACCESS_TOKEN, and refresh token as GUSTO_REFRESH_TOKEN. Access tokens expire every 2 hours; refresh using /oauth/token with grant_type=refresh_token.
Required scopes
contractors:read, contractors:write, contractor_payments:read, contractor_payments:write, companies:read
Webhook / trigger setup
No inbound webhook required at current volume. Gusto does offer webhook subscriptions for contractor.created and contractor_payment.created events via the Partner API — configure if payment confirmation logging to HubSpot is required as a future enhancement.
Required configuration
Gusto company UUID must be stored as GUSTO_COMPANY_UUID. The automation creates contractors via POST /v1/companies/{companyUuid}/contractors. Required fields: type (Individual), first_name, last_name, email, start_date. Bank account details are added in a separate call to /v1/contractors/{contractorUuid}/bank_accounts using the bank account information stored securely in the credential store as part of the contractor onboarding data collected from Google Drive. Confirm with the client that their Gusto plan includes API/integration access before build.
Rate limits
Gusto API: 100 requests/minute. At 12 new contractors/month, this limit is not approached. No throttling needed. Implement standard 429 retry with exponential back-off.
Constraints
Gusto API access tier varies by subscription plan — the Plus plan or above is required. Contractor bank account details must be handled with strict security; never log raw bank account numbers. The automation must confirm that the DocuSign agreement status is 'completed' and all Google Drive compliance documents are filed before initiating the Gusto payee creation call.
// Input — create contractor payee
POST /v1/companies/{GUSTO_COMPANY_UUID}/contractors
{ type: 'Individual', first_name, last_name, email, start_date }
// Input — add bank account (separate call)
POST /v1/contractors/{contractorUuid}/bank_accounts
{ routing_number, account_number, account_type: 'Checking' | 'Savings' }
// Output
{ uuid: gusto_contractor_uuid, email, start_date, payment_method: 'Direct Deposit' }Integration and API SpecPage 2 of 4
FS-DOC-05Technical
03Field mappings between tools
The tables below define the exact field mappings for each agent handoff. Source and destination field names are given in their native API format. Use these as the canonical reference when configuring field mappings in the orchestration layer.
Agent 1 handoff 1: Form submission trigger to HubSpot contact creation
Source tool
Source field
Destination tool
Destination field
Form / trigger payload
`first_name`
HubSpot
`firstname`
Form / trigger payload
`last_name`
HubSpot
`lastname`
Form / trigger payload
`email_address`
HubSpot
`email`
Form / trigger payload
`phone_number`
HubSpot
`phone`
Form / trigger payload
`contractor_role`
HubSpot
`jobtitle`
Form / trigger payload
`agreed_rate`
HubSpot
`agreed_rate_usd`
Form / trigger payload
`engagement_start_date`
HubSpot
`start_date`
Form / trigger payload
`contractor_type`
HubSpot
`contractor_type`
Static value
`'contractor'`
HubSpot
`hs_lifecycle_stage`
Agent 1 handoff 2: HubSpot contact to DocuSign envelope
Source tool
Source field
Destination tool
Destination field
HubSpot
`firstname` + `lastname`
DocuSign
`templateRoles[].name`
HubSpot
`email`
DocuSign
`templateRoles[].email`
HubSpot
`agreed_rate_usd`
DocuSign tab
`agreed_rate_usd` (Text tab)
HubSpot
`start_date`
DocuSign tab
`engagement_start_date` (Text tab)
HubSpot
`jobtitle`
DocuSign tab
`role_title` (Text tab)
HubSpot
`contractor_type`
Credential store lookup
`DOCUSIGN_TEMPLATE_ID_{type}`
DocuSign response
`envelopeId`
HubSpot
`docusign_envelope_id`
Agent 1 handoff 3: Google Drive filed document metadata to HubSpot contact note
Source tool
Source field
Destination tool
Destination field
Google Drive
`id` (file ID)
HubSpot note body
`gdrive_file_id`
Google Drive
`webViewLink`
HubSpot note body
`gdrive_file_url`
Google Drive
`modifiedTime`
HubSpot note body
`filed_at_utc`
Automation logic
`document_type` (derived from filename)
HubSpot
`compliance_status` (updated to `complete` when all types received)
Agent 2 handoff 1: Invoice intake to HubSpot rate verification
Source tool
Source field
Destination tool
Destination field
Invoice email / form
`contractor_email`
HubSpot lookup
`email` (find contact)
Invoice email / form
`invoice_amount`
HubSpot
`last_invoice_amount_usd`
Invoice email / form
`invoice_date`
HubSpot
`last_invoice_date`
HubSpot
`agreed_rate_usd`
Automation logic
Rate match comparison value
Automation logic
`match_result`
HubSpot
`invoice_approval_status` set to `pending`
Agent 2 handoff 2: Slack approval action to Xero bill creation
Source tool
Source field
Destination tool
Destination field
Slack action payload
`value.contractor_id`
Xero
`Contact.ContactID` (looked up by email)
Slack action payload
`value.invoice_amount_usd`
Xero
`LineItems[].UnitAmount`
HubSpot
`jobtitle`
Xero
`LineItems[].Description`
Automation logic
today + `XERO_PAYMENT_DUE_DAYS`
Xero
`DueDate`
Credential store
`XERO_CONTRACTOR_ACCOUNT_CODE`
Xero
`LineItems[].AccountCode`
Slack action payload
`value.xero_draft_bill_id`
Xero
`InvoiceID` (finalise draft)
Xero response
`InvoiceID`
HubSpot
`xero_bill_id`
Agent 2 handoff 3: Xero bill confirmation to Gusto payment and contractor notification
Source tool
Source field
Destination tool
Destination field
HubSpot
`gusto_contractor_uuid`
Gusto
`contractorUuid` (payment target)
Xero
`AmountDue`
Gusto
Payment amount (manual confirmation step)
Xero
`DueDate`
Gusto
Payment date
Xero
`InvoiceNumber`
Email to contractor
Payment reference in notification body
HubSpot
`email`
Email / Slack DM
Contractor confirmation recipient
04Build stack and orchestration
Orchestration layout
Two discrete workflows, one per agent. Workflow 1: Contractor Onboarding Agent. Workflow 2: Invoice Processing Agent. Both workflows share a single credential store (environment secret vault) provisioned within the automation platform. No credentials are hardcoded in workflow logic.
Agent 1 trigger mechanism
Webhook (push). HubSpot fires a contact.creation webhook when a new contact with hs_lifecycle_stage = contractor is detected, or when a form submission is received. The automation platform exposes an HTTPS endpoint to receive this event. Signature validation is performed using X-HubSpot-Signature-v3 HMAC-SHA256 before any processing begins. Fallback: a 15-minute poll of HubSpot new contacts (filtered by lifecycle stage and created_at) runs in parallel to catch any webhook delivery failures.
Agent 1 DocuSign completion trigger
Webhook (push). DocuSign Connect fires an Envelope Completed or Envelope Declined event to the automation platform's inbound HTTPS endpoint. The X-DocuSign-Signature-1 HMAC header is validated using DOCUSIGN_CONNECT_HMAC_KEY before the Gusto payee creation step is initiated.
Agent 1 Google Drive document detection
Poll (15-minute interval). The automation platform polls the GDRIVE_INTAKE_FOLDER_ID for new files using the Drive Files: list API filtered by modifiedTime greater than the last-run timestamp. A push Watch channel may be added as an optimisation post-launch.
Agent 2 trigger mechanism
Webhook (push) for invoice email parsing, or poll (30-minute interval) for invoice submission form entries. The invoice intake endpoint validates the source IP range or shared secret token before processing. Slack approval action responses arrive via the Interactivity Request URL (push), validated with X-Slack-Signature HMAC-SHA256 using SLACK_SIGNING_SECRET.
Shared credential store contents
See code block below. All secrets are injected as environment variables at runtime. No secret is written to workflow logs.
Inter-agent data passing
HubSpot contact record acts as the shared state object between agents. Agent 1 writes contractor data, DocuSign IDs, and compliance status. Agent 2 reads rate data and writes invoice approval outcomes and Xero bill IDs. No direct inter-workflow call is made; HubSpot is the shared data bus.
Credential store contents — automation platform secret vault
# Credential Store — all values injected as environment variables at runtime
# Never log, print, or hardcode any of these values
# HubSpot
HUBSPOT_API_TOKEN=<private-app-token>
HUBSPOT_WEBHOOK_CLIENT_SECRET=<app-client-secret-for-signature-validation>
# DocuSign
DOCUSIGN_INTEGRATION_KEY=<integration-key-uuid>
DOCUSIGN_RSA_PRIVATE_KEY=<rsa-private-key-pem>
DOCUSIGN_ACCOUNT_ID=<docusign-account-uuid>
DOCUSIGN_BASE_URI=https://na4.docusign.net
DOCUSIGN_IMPERSONATION_USER_ID=<admin-user-guid>
DOCUSIGN_CONNECT_HMAC_KEY=<connect-webhook-hmac-key>
DOCUSIGN_TEMPLATE_ID_STANDARD=<template-uuid>
DOCUSIGN_TEMPLATE_ID_NDA_ONLY=<template-uuid>
# Google Drive
GOOGLE_SERVICE_ACCOUNT_JSON=<json-key-file-contents>
GDRIVE_ROOT_FOLDER_ID=<folder-id>
GDRIVE_INTAKE_FOLDER_ID=<folder-id>
# Slack
SLACK_BOT_TOKEN=xoxb-<token>
SLACK_SIGNING_SECRET=<signing-secret>
SLACK_HR_CHANNEL_ID=<channel-id>
SLACK_FINANCE_CHANNEL_ID=<channel-id>
# Xero
XERO_CLIENT_ID=<client-id>
XERO_CLIENT_SECRET=<client-secret>
XERO_ACCESS_TOKEN=<short-lived-token> # refreshed at runtime
XERO_REFRESH_TOKEN=<60-day-rolling-token>
XERO_TENANT_ID=<organisation-uuid>
XERO_CONTRACTOR_ACCOUNT_CODE=200
XERO_PAYMENT_DUE_DAYS=14
# Gusto
GUSTO_CLIENT_ID=<client-id>
GUSTO_CLIENT_SECRET=<client-secret>
GUSTO_ACCESS_TOKEN=<access-token> # refreshed every 2 hours
GUSTO_REFRESH_TOKEN=<refresh-token>
GUSTO_COMPANY_UUID=<company-uuid>
Integration and API SpecPage 3 of 4
FS-DOC-05Technical
05Error handling and retry logic
Unhandled exceptions must never fail silently. Every integration point must either complete successfully, trigger a defined retry sequence, or route the failure to an alert (Slack SLACK_HR_CHANNEL_ID or SLACK_FINANCE_CHANNEL_ID) with enough context for a human to intervene. Dead-letter events must be logged to a persistent error table in the automation platform with the timestamp, integration name, payload snapshot, and error code.
Integration
Scenario
Required behaviour
HubSpot webhook
Webhook signature validation fails (tampered or replayed request)
Reject with HTTP 401. Log rejection with source IP and timestamp. Do not process payload. Alert to SLACK_HR_CHANNEL_ID if more than 3 failures in 10 minutes.
HubSpot API
Contact creation returns 429 (rate limit hit)
Pause workflow for 10 seconds, retry up to 3 times with exponential back-off (10s, 30s, 90s). If still failing after 3 retries, post alert to SLACK_HR_CHANNEL_ID with contractor name and abort the run. Log to error table.
HubSpot API
Contact creation returns 409 (duplicate contact)
Check if existing contact has hs_lifecycle_stage = contractor. If yes, update the record rather than creating. If no, flag for manual review in SLACK_HR_CHANNEL_ID and halt further processing for that contact.
DocuSign
Envelope send fails (invalid template ID or recipient email)
Retry once after 60 seconds. If still failing, post alert to SLACK_HR_CHANNEL_ID with contractor name, error code, and suggested fix. Update HubSpot contact compliance_status to flagged. Do not retry more than once — manual correction of the template or email is required.
DocuSign
Envelope status remains pending beyond 5 business days (slow or non-responsive signer)
Agent 1 chase logic: send reminder email to contractor on day 3 and day 5. Post escalation alert to SLACK_HR_CHANNEL_ID on day 5. If no completion by day 7, void envelope, notify HR via Slack, and set compliance_status = flagged in HubSpot. Do not void silently.
DocuSign Connect
Webhook delivery fails (automation platform unreachable)
DocuSign retries webhook delivery up to 8 times over 72 hours. The automation platform must return HTTP 200 within 3 seconds or DocuSign marks delivery failed. Implement the HubSpot poll fallback (15-minute interval on envelope status) to catch any missed completions.
Google Drive
File upload or move operation fails (permission denied or quota exceeded)
Retry up to 3 times with 30-second back-off. If still failing, post alert to SLACK_HR_CHANNEL_ID with file name, contractor ID, and error. Do not proceed to Gusto payee creation until all compliance documents are confirmed filed. Log failed file operation to error table.
Slack
Invoice approval message fails to deliver (invalid channel ID or bot not in channel)
Retry once after 30 seconds. If still failing, fall back to sending an email to the manager's address (looked up from HubSpot). Log delivery failure to error table. Post alert to SLACK_FINANCE_CHANNEL_ID.
Slack
Manager does not respond to invoice approval message within 48 hours
Send a reminder Slack DM to the manager at 24 hours. At 48 hours, escalate by posting to SLACK_FINANCE_CHANNEL_ID tagging the finance admin. Update HubSpot invoice_approval_status to pending_escalated. Do not auto-approve. Do not allow the Xero bill to be created without explicit approval.
Xero
Access token expired at time of API call
Refresh token using XERO_REFRESH_TOKEN before retrying the original call. If refresh fails (refresh token expired or revoked), halt the workflow, post alert to SLACK_FINANCE_CHANNEL_ID with instruction to re-authorise the Xero connection, and log to error table. Implement a scheduled daily token keep-alive to prevent 60-day expiry.
Xero
Bill creation returns 400 (invalid account code or missing contact)
If contact not found: create Xero contact from HubSpot data first, then retry bill creation. If account code invalid: alert SLACK_FINANCE_CHANNEL_ID to confirm the correct code and halt bill creation. Do not substitute a default code silently.
Gusto
Contractor payee creation fails (plan does not include API access or duplicate contractor)
If API access error (403): halt Agent 1 payee creation step, post alert to SLACK_HR_CHANNEL_ID with instructions to confirm Gusto plan tier. If duplicate (contractor already exists): retrieve existing UUID, store to HubSpot as gusto_contractor_uuid, and continue. Log all Gusto errors to error table with full response body.
All error table entries must include at minimum: timestamp (UTC), integration name, workflow name, agent name (Agent 1 or Agent 2), HTTP status code, response body excerpt (truncated to 500 characters), contractor ID or email if available, and the action taken (retried, alerted, halted). The FullSpec team reviews error table entries during the QA phase and will configure alerting thresholds before go-live. Contact support@gofullspec.com if you observe unexpected error volumes after launch.
Integration and API SpecPage 4 of 4