Back to Commission & Payout Calculation

Integration and API Spec

The reference during the build: every tool connection, auth scope, field mapping, and error-handling rule.

4 pagesPDF · Technical
FS-DOC-05Technical

Integration and API Spec

Commission and Payout Calculation

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

This document is the definitive technical reference for every external service connection used in the Commission and Payout Calculation automation. It covers authentication methods, required OAuth scopes, webhook and polling setup, field mappings between agents, credential storage conventions, rate-limit analysis at current volume, and failure behaviour for every integration point. FullSpec uses this document to build and configure each agent workflow; your team uses it to provision credentials, review access grants, and validate that the correct scopes are in place before the build begins.

01Tool inventory

Tool
Role in automation
Auth method
Min plan required
Used by agents
HubSpot
Source of closed-won deal records; queried via scheduled API call each pay period
OAuth 2.0 (private app token)
Sales Hub Starter or above (API access required)
Agent 1 (Deal Ingestion)
Google Sheets
Rate table storage and structured payout ledger; read and written by calculation agent
OAuth 2.0 (service account)
Google Workspace Business Starter or any plan with Sheets API enabled
Agent 2 (Commission Calculation)
Slack
Manager approval gate and rep payout notifications; interactive message with button payload
OAuth 2.0 (Bot Token, Slack App)
Any paid Slack plan (for interactive messages and DM API access)
Agent 3 (Payout Distribution)
Gusto
Payroll additional earnings entry; per-rep commission total pushed as additional earning line
OAuth 2.0 (authorization code flow)
Gusto Plus or Gusto Premium (API access enabled by Gusto support)
Agent 3 (Payout Distribution)
Xero
Commission expense journal entry creation; coded to cost centre for the pay period
OAuth 2.0 (authorization code flow, PKCE)
Xero Starter or above (accounting API included on all plans)
Agent 3 (Payout Distribution)
Automation platform
Orchestration and scheduling layer; hosts all three agent workflows, credential store, retry logic, and schedule triggers
Internal service credential store
Current subscription at $150/month (Standard build)
All agents
Before you connect anything: provision and test every integration in a sandbox or development environment using non-production credentials before any production token or live payroll account is connected. HubSpot, Xero, and Gusto all provide sandbox tenants. Slack apps should be installed in a test workspace first. Production credentials must never appear in a workflow that has not passed the full QA cycle.

02Per-tool integration detail

HubSpot

Used by the Deal Ingestion Agent (Agent 1) to retrieve all closed-won deals within the pay period date range. Connection is polled on a schedule aligned to pay period close; no inbound webhook from HubSpot is required.

Auth method
OAuth 2.0 via HubSpot Private App. Generate a private app token in HubSpot Settings > Integrations > Private Apps. Token is long-lived (no expiry by default) but must be rotated on a 90-day schedule. Store token in the credential store under the key HUBSPOT_API_TOKEN.
Required scopes
crm.objects.deals.read, crm.objects.contacts.read, crm.objects.owners.read, crm.schemas.deals.read
Webhook / trigger setup
No inbound webhook required. The automation platform polls the HubSpot CRM API on a scheduled trigger at pay period close. The poll queries GET /crm/v3/objects/deals with filters closedate__gte and closedate__lte set to the period start and end, and dealstage equal to the closed-won stage ID. The closed-won stage ID must be retrieved from the pipeline configuration and stored in the credential store as HUBSPOT_CLOSEDWON_STAGE_ID. Do not hardcode.
Required configuration
Pipeline ID stored as HUBSPOT_PIPELINE_ID. Closed-won stage ID stored as HUBSPOT_CLOSEDWON_STAGE_ID. Custom deal properties for rep quota attainment tier (if present) must be confirmed with the HubSpot admin and their internal property names stored in the workflow config. Date range for the pay period is passed as runtime parameters by the schedule trigger, not hardcoded.
Rate limits
HubSpot enforces 100 requests per 10 seconds and 40,000 requests per day on the CRM API for Private Apps on Sales Hub Starter. At current volume of 40 to 120 deal records per pay period, a single poll run will consume approximately 3 to 8 API calls (pagination at 100 records per page). No throttling logic is required at this volume; however, implement exponential backoff on 429 responses as a precaution.
Constraints
The closed-won stage ID is pipeline-specific and will differ between HubSpot portals. Do not assume a default value. Custom deal properties used for rep assignment or product line must be present in the portal before the ingestion agent is deployed. The API returns a maximum of 100 objects per page; pagination must be implemented using the paging.next.after cursor.
// Input
period_start: ISO 8601 date string
period_end:   ISO 8601 date string
// Output
deals[]: { deal_id, deal_name, amount, close_date, owner_id, pipeline_id, dealstage, product_line, split_flag }
Google Sheets

Used by both the Deal Ingestion Agent (Agent 1) and the Commission Calculation Agent (Agent 2). Agent 1 writes the cleaned deal list. Agent 2 reads the commission rate table and writes the per-rep payout summary. Two named sheets must exist in the designated spreadsheet.

Auth method
OAuth 2.0 via a Google Cloud service account. Create a service account in the Google Cloud Console, generate a JSON key file, and share the target spreadsheet with the service account email address (editor access). Store the full JSON key contents in the credential store under GOOGLE_SERVICE_ACCOUNT_JSON. Do not store as a file path.
Required scopes
https://www.googleapis.com/auth/spreadsheets, https://www.googleapis.com/auth/drive.file
Webhook / trigger setup
No webhook. Agent 2 is triggered by a completion event from Agent 1 within the orchestration layer, not by a Sheets-native trigger.
Required configuration
Spreadsheet ID stored as SHEETS_COMMISSION_SPREADSHEET_ID. Sheet tab names must be exactly: 'deal_list' (written by Agent 1), 'rate_table' (maintained by finance team, read by Agent 2), 'payout_summary' (written by Agent 2). The rate_table sheet must follow the defined schema: columns rep_id, tier_label, attainment_min_pct, attainment_max_pct, commission_rate_pct. No merged cells, no blank header rows, row 1 is always the header. The spreadsheet ID must not be hardcoded in workflow logic.
Rate limits
Google Sheets API enforces 60 read requests per minute per user and 300 requests per minute per project. At current volume, each agent run performs 3 to 6 API calls (read rate table, read deal list, write payout summary). No throttling is required. Batch writes using batchUpdate are preferred over per-row updates to minimise call count.
Constraints
The rate_table sheet must be locked against accidental edits by non-automation users using Google Sheets protected range settings. Agent 2 must treat any row in the rate_table with a missing or non-numeric commission_rate_pct value as an exception and surface it before processing deals against that tier. The automation platform must not cache the rate table between runs; it must be re-read at the start of each pay period cycle.
// Input (Agent 2 reads)
sheet: 'deal_list'  -> deal records written by Agent 1
sheet: 'rate_table' -> rep_id, tier_label, attainment_min_pct, attainment_max_pct, commission_rate_pct
// Output (Agent 2 writes)
sheet: 'payout_summary' -> rep_id, rep_name, deal_count, total_revenue, tier_applied, gross_commission, period_label
Slack

Used by the Payout Distribution Agent (Agent 3) for two distinct functions: posting an interactive approval message to the manager, and sending personalised direct messages to each rep after approval. A single Slack Bot App with the required scopes handles both.

Auth method
OAuth 2.0 Bot Token. Create a Slack App in api.slack.com, install it to the workspace, and copy the Bot User OAuth Token (xoxb- prefix). Store under SLACK_BOT_TOKEN. The Slack Signing Secret must also be stored as SLACK_SIGNING_SECRET for validating inbound interaction payloads.
Required scopes
chat:write, im:write, channels:read, users:read, users:read.email, incoming-webhook (for approval channel post)
Webhook / trigger setup
Outbound: the automation platform calls the Slack chat.postMessage API to post the approval summary to the manager's channel or DM. Inbound: the manager's button click sends an HTTP POST to the automation platform's Slack interaction endpoint. The endpoint URL must be registered in the Slack App configuration under Interactivity and Shortcuts. Every inbound payload must be signature-validated using the SLACK_SIGNING_SECRET (HMAC-SHA256 of the raw request body against the signing secret) before the workflow resumes. The approval block must include a unique payload_id tied to the pay period label to prevent replay of stale approvals.
Required configuration
Manager's Slack user ID or channel ID stored as SLACK_MANAGER_USER_ID. Interaction endpoint URL registered in the Slack App settings (must be HTTPS). Approval message block kit template must include: period label, rep count, total payout amount, an Approve button, and a Flag for Review button. Message template stored in the workflow config, not hardcoded in the agent logic. Rep Slack user IDs mapped from HubSpot owner_id in a lookup table stored in the credential store as SLACK_USER_ID_MAP (JSON object).
Rate limits
Slack Web API enforces 1 request per second per method for tier 3 methods including chat.postMessage. At current volume of up to 10 reps per pay period, plus 1 manager message, the agent sends a maximum of 11 messages per run. No throttling layer is required; however, a 1-second delay between DM sends is recommended to remain inside the burst limit.
Constraints
The workflow must not proceed to Gusto or Xero steps unless the inbound interaction payload confirms action_id equals 'approve_payout' and the signature validation passes. A Flag for Review response must halt the workflow and post a notification to the finance team channel. Approval messages older than 48 hours must be treated as expired and the workflow must surface an alert rather than wait indefinitely.
// Outbound (approval message)
POST chat.postMessage -> channel: SLACK_MANAGER_USER_ID
  payload: { period_label, rep_count, total_payout_usd, blocks: [approval_table, approve_btn, flag_btn] }
// Inbound (interaction callback)
POST <interaction_endpoint> -> { action_id, payload_id, user_id, ts }
// Outbound (rep DM)
POST chat.postMessage -> channel: rep_slack_user_id
  payload: { period_label, deals[], rate_applied, gross_commission }
Integration and API SpecPage 1 of 3
FS-DOC-05Technical
Gusto

Used by the Payout Distribution Agent (Agent 3) to push each rep's approved commission total as an additional earnings line item for the current pay run. Connection requires Gusto API access to be enabled on the account by Gusto support before credentials can be provisioned.

Auth method
OAuth 2.0 authorization code flow. Register the automation platform as an OAuth application in the Gusto Developer Portal. Store the access token under GUSTO_ACCESS_TOKEN and the refresh token under GUSTO_REFRESH_TOKEN. Tokens expire after 2 hours; the workflow must implement a token refresh cycle using the refresh token before each Gusto API call. Store the client ID and secret as GUSTO_CLIENT_ID and GUSTO_CLIENT_SECRET.
Required scopes
payrolls:write, employees:read, companies:read
Webhook / trigger setup
No inbound webhook. Agent 3 calls the Gusto API after receiving a confirmed approval signal from the Slack interaction handler. The agent identifies the correct pay run using GET /v1/companies/{company_id}/payrolls filtered by pay period dates, then updates the payroll using PUT /v1/companies/{company_id}/payrolls/{payroll_id} with additional earnings entries per employee.
Required configuration
Gusto company ID stored as GUSTO_COMPANY_ID. Employee ID to HubSpot owner_id mapping stored as GUSTO_EMPLOYEE_ID_MAP (JSON object in the credential store). The additional earnings type code for commissions must be confirmed with the Gusto account admin and stored as GUSTO_COMMISSION_EARNING_TYPE_ID. Do not hardcode employee IDs or earning type codes.
Rate limits
Gusto enforces 60 requests per minute on the Embedded Payroll API. At current volume of up to 10 rep entries per pay period, the agent makes approximately 12 to 15 API calls per run (1 payroll fetch, up to 10 employee updates, 1 to 2 validation reads). No throttling is required. Implement exponential backoff on 429 responses.
Constraints
The target pay run must be in an open state; Gusto will reject writes to a locked or processed payroll. The workflow must check payroll status before attempting to write and surface an alert if the payroll is already locked. Commission amounts must be in whole cents (integer, not float). Any employee ID not found in GUSTO_EMPLOYEE_ID_MAP must be treated as an exception and must not be silently skipped.
// Input
approved_payouts[]: { hubspot_owner_id, rep_name, gross_commission_usd }
// Lookup
GUSTO_EMPLOYEE_ID_MAP: { hubspot_owner_id -> gusto_employee_id }
// API call
PUT /v1/companies/{GUSTO_COMPANY_ID}/payrolls/{payroll_id}
  body: { employee_compensations: [{ employee_id, additional_earnings: [{ earning_type_id, amount }] }] }
Xero

Used by the Payout Distribution Agent (Agent 3) to create a commission expense journal entry after payouts are approved and pushed to Gusto. The journal entry codes the total commission expense to the correct cost centre and attaches the approved payout summary as a supporting document.

Auth method
OAuth 2.0 authorization code flow with PKCE. Register the automation platform as a Xero App in the Xero Developer Portal. Store the access token as XERO_ACCESS_TOKEN and the refresh token as XERO_REFRESH_TOKEN. Access tokens expire after 30 minutes; refresh tokens expire after 60 days and must be exchanged before each run if the workflow does not run more frequently than that. Store client ID and secret as XERO_CLIENT_ID and XERO_CLIENT_SECRET. Tenant (organisation) ID must be stored as XERO_TENANT_ID.
Required scopes
accounting.journals.read, accounting.journals.write, accounting.settings.read, offline_access
Webhook / trigger setup
No inbound webhook. Agent 3 calls the Xero API after the Gusto write step completes successfully. Journal entry is created via POST /api.xro/2.0/ManualJournals.
Required configuration
Xero tenant ID stored as XERO_TENANT_ID. Commission expense account code stored as XERO_COMMISSION_EXPENSE_CODE. Payroll liability account code stored as XERO_PAYROLL_LIABILITY_CODE. Tax type code for commission entries stored as XERO_TAX_TYPE (typically NONE or EXEMPTEXPENSES depending on jurisdiction; confirm with the bookkeeper). Cost centre tracking category ID stored as XERO_TRACKING_CATEGORY_ID. No account codes or category IDs to be hardcoded.
Rate limits
Xero enforces 60 API calls per minute and 5,000 calls per day on all plans. Each agent run makes 1 to 2 API calls to Xero (one ManualJournals POST, one optional Attachments PUT). No throttling required at current volume. Implement 429 backoff handling.
Constraints
The journal entry must include the period label in the Narration field for audit traceability. The debit line must reference XERO_COMMISSION_EXPENSE_CODE and the credit line must reference XERO_PAYROLL_LIABILITY_CODE. Both lines must balance to zero. If the Gusto write step did not complete successfully, the Xero step must not execute; create a partial-completion alert instead. The approved payout summary (Google Sheets URL or exported PDF) must be attached to the journal entry as a supporting document.
// Input
total_commission_usd: number
period_label: string
payout_sheet_url: string
// API call
POST /api.xro/2.0/ManualJournals
  body: { Narration, Date, JournalLines: [
    { LineAmount: +total, AccountCode: XERO_COMMISSION_EXPENSE_CODE, TaxType, Tracking },
    { LineAmount: -total, AccountCode: XERO_PAYROLL_LIABILITY_CODE, TaxType }
  ] }

03Field mappings between tools

The tables below document every field-level mapping across agent handoffs. Monospace field names reflect the exact property keys used in API responses and sheet column headers. All mappings are read by the orchestration layer at runtime; no values are hardcoded.

Handoff 1: Deal Ingestion Agent (HubSpot to Google Sheets deal_list)

Source tool
Source field
Destination tool
Destination field
HubSpot
`properties.hs_object_id`
Google Sheets
`deal_id`
HubSpot
`properties.dealname`
Google Sheets
`deal_name`
HubSpot
`properties.amount`
Google Sheets
`deal_value_usd`
HubSpot
`properties.closedate`
Google Sheets
`close_date`
HubSpot
`properties.hubspot_owner_id`
Google Sheets
`owner_id`
HubSpot
`properties.pipeline`
Google Sheets
`pipeline_id`
HubSpot
`properties.dealstage`
Google Sheets
`deal_stage`
HubSpot
`properties.hs_deal_stage_probability`
Google Sheets
`stage_probability`
HubSpot
`properties.product_line` (custom)
Google Sheets
`product_line`
HubSpot
`properties.commission_split_flag` (custom)
Google Sheets
`split_flag`
Automation platform
runtime: `period_label`
Google Sheets
`period_label`
Automation platform
runtime: `run_timestamp`
Google Sheets
`ingested_at`

Handoff 2: Commission Calculation Agent (Google Sheets rate_table + deal_list to payout_summary)

Source tool
Source field
Destination tool
Destination field
Google Sheets deal_list
`owner_id`
Google Sheets payout_summary
`rep_id`
Google Sheets deal_list
`deal_value_usd`
Google Sheets payout_summary
`total_revenue_usd`
Google Sheets deal_list
`deal_id`
Google Sheets payout_summary
`deal_ids_list`
Google Sheets deal_list
`period_label`
Google Sheets payout_summary
`period_label`
Google Sheets rate_table
`commission_rate_pct`
Google Sheets payout_summary
`rate_applied_pct`
Google Sheets rate_table
`tier_label`
Google Sheets payout_summary
`tier_applied`
Calculation agent
computed: `deal_value_usd * rate_applied_pct`
Google Sheets payout_summary
`gross_commission_usd`
Calculation agent
computed: `COUNT(deal_ids_list)`
Google Sheets payout_summary
`deal_count`
Calculation agent
computed: exception flag
Google Sheets payout_summary
`exception_flag`
Calculation agent
computed: exception reason string
Google Sheets payout_summary
`exception_reason`

Handoff 3: Payout Distribution Agent (Google Sheets payout_summary to Gusto)

Source tool
Source field
Destination tool
Destination field
Google Sheets payout_summary
`rep_id`
Gusto
`employee_id` (via GUSTO_EMPLOYEE_ID_MAP)
Google Sheets payout_summary
`gross_commission_usd`
Gusto
`additional_earnings[].amount` (in cents)
Credential store
`GUSTO_COMMISSION_EARNING_TYPE_ID`
Gusto
`additional_earnings[].earning_type_id`
Credential store
`GUSTO_COMPANY_ID`
Gusto
URL path parameter `{company_id}`
Automation platform
runtime: `payroll_id` (fetched from payrolls list)
Gusto
URL path parameter `{payroll_id}`

Handoff 4: Payout Distribution Agent (Google Sheets payout_summary to Xero)

Source tool
Source field
Destination tool
Destination field
Google Sheets payout_summary
`SUM(gross_commission_usd)`
Xero
`JournalLines[0].LineAmount` (debit, positive)
Google Sheets payout_summary
`period_label`
Xero
`Narration`
Credential store
`XERO_COMMISSION_EXPENSE_CODE`
Xero
`JournalLines[0].AccountCode`
Credential store
`XERO_PAYROLL_LIABILITY_CODE`
Xero
`JournalLines[1].AccountCode`
Credential store
`XERO_TRACKING_CATEGORY_ID`
Xero
`JournalLines[0].Tracking[0].TrackingCategoryID`
Credential store
`XERO_TAX_TYPE`
Xero
`JournalLines[].TaxType`
Automation platform
runtime: `payout_sheet_url`
Xero
Attachment URL on ManualJournal

Handoff 5: Payout Distribution Agent (Google Sheets payout_summary to Slack rep DMs)

Source tool
Source field
Destination tool
Destination field
Google Sheets payout_summary
`rep_id`
Slack
`channel` (via SLACK_USER_ID_MAP)
Google Sheets payout_summary
`rep_name`
Slack
message `text` greeting field
Google Sheets payout_summary
`deal_ids_list`
Slack
message block: deal list section
Google Sheets payout_summary
`deal_count`
Slack
message block: deal count summary line
Google Sheets payout_summary
`total_revenue_usd`
Slack
message block: total revenue line
Google Sheets payout_summary
`rate_applied_pct`
Slack
message block: commission rate line
Google Sheets payout_summary
`gross_commission_usd`
Slack
message block: gross commission line
Google Sheets payout_summary
`period_label`
Slack
message block: period header
Integration and API SpecPage 2 of 3
FS-DOC-05Technical

04Build stack and orchestration

Orchestration layout
Three separate named workflows, one per agent: 'deal-ingestion-agent', 'commission-calculation-agent', 'payout-distribution-agent'. Each workflow is self-contained with its own error handling and logging. Inter-agent handoffs are triggered by completion events within the orchestration layer, not by time-based polling between agents. All three workflows share a single credential store namespace: 'commission-payout'.
Agent 1 trigger mechanism
Schedule-based poll. The 'deal-ingestion-agent' workflow is triggered by a cron-style schedule configured to fire at pay period close (e.g. last business day of each bi-weekly period or month end). The schedule parameters (frequency, timezone, period_start offset) are stored in the workflow config, not hardcoded. No inbound webhook is used for this agent. The trigger passes a runtime context object containing period_label, period_start, and period_end.
Agent 2 trigger mechanism
Completion event from Agent 1. The 'commission-calculation-agent' is triggered when the 'deal-ingestion-agent' emits a success completion event and the deal_list sheet row count exceeds zero. If Agent 1 returns zero records, Agent 2 does not execute and the orchestration layer posts an alert to the finance team Slack channel.
Agent 3 trigger mechanism
Two-stage: first trigger is a completion event from Agent 2, which causes the Payout Distribution Agent to post the Slack approval message and then pause (await interaction). Second trigger is the inbound Slack interaction webhook. The interaction payload is validated using HMAC-SHA256 signature verification (SLACK_SIGNING_SECRET) before the workflow resumes. A flag button response halts the workflow and sends an alert; an approve response proceeds to Gusto and Xero steps. If no interaction is received within 48 hours, the workflow times out and posts an expiry alert.
Credential store namespace
All secrets referenced in workflow logic are resolved at runtime from the credential store. No credential value appears in workflow node configuration or code. See the credential store manifest below.
Credential store manifest — commission-payout namespace. All [config] entries are non-secret but must still be stored in the credential store and never hardcoded in workflow logic.
// Credential store manifest — namespace: commission-payout
// All entries are secret-type unless marked [config]

HUBSPOT_API_TOKEN                  // HubSpot Private App token
HUBSPOT_PIPELINE_ID                // [config] HubSpot deal pipeline ID
HUBSPOT_CLOSEDWON_STAGE_ID         // [config] HubSpot closed-won stage ID

GOOGLE_SERVICE_ACCOUNT_JSON        // Full JSON key for Google service account
SHEETS_COMMISSION_SPREADSHEET_ID   // [config] Target spreadsheet ID

SLACK_BOT_TOKEN                    // Slack Bot User OAuth Token (xoxb-...)
SLACK_SIGNING_SECRET               // Slack App signing secret for payload validation
SLACK_MANAGER_USER_ID              // [config] Slack user ID of approving manager
SLACK_USER_ID_MAP                  // [config] JSON: { hubspot_owner_id: slack_user_id }

GUSTO_CLIENT_ID                    // Gusto OAuth client ID
GUSTO_CLIENT_SECRET                // Gusto OAuth client secret
GUSTO_ACCESS_TOKEN                 // Gusto access token (refreshed before each run)
GUSTO_REFRESH_TOKEN                // Gusto refresh token
GUSTO_COMPANY_ID                   // [config] Gusto company UUID
GUSTO_EMPLOYEE_ID_MAP              // [config] JSON: { hubspot_owner_id: gusto_employee_id }
GUSTO_COMMISSION_EARNING_TYPE_ID   // [config] Gusto earning type code for commissions

XERO_CLIENT_ID                     // Xero OAuth client ID
XERO_CLIENT_SECRET                 // Xero OAuth client secret
XERO_ACCESS_TOKEN                  // Xero access token (refreshed before each run)
XERO_REFRESH_TOKEN                 // Xero refresh token
XERO_TENANT_ID                     // [config] Xero organisation tenant ID
XERO_COMMISSION_EXPENSE_CODE       // [config] Xero account code: commission expense
XERO_PAYROLL_LIABILITY_CODE        // [config] Xero account code: payroll liability
XERO_TRACKING_CATEGORY_ID          // [config] Xero tracking category ID for cost centre
XERO_TAX_TYPE                      // [config] Xero tax type string (e.g. NONE)
Token rotation: GUSTO_ACCESS_TOKEN and XERO_ACCESS_TOKEN must be refreshed programmatically before every workflow execution that calls those APIs. The orchestration layer must persist the new access token and refresh token back to the credential store after each successful refresh. Failure to refresh must trigger an alert and halt the affected workflow step rather than proceeding with an expired token.

05Error handling and retry logic

Every integration point has a defined failure behaviour. Unhandled exceptions must never fail silently. All errors must be logged to the orchestration platform's run history with full context (agent name, step name, HTTP status code or error message, payload excerpt, timestamp) and a notification sent to the finance team Slack channel unless the error is resolved by a retry.

Integration
Scenario
Required behaviour
HubSpot (Agent 1)
API returns 429 Too Many Requests
Retry with exponential backoff: wait 10 s, 30 s, 60 s (max 3 attempts). If all retries fail, halt Agent 1 and post alert to finance Slack channel with period label and error detail. Do not proceed to Agent 2.
HubSpot (Agent 1)
API returns 401 Unauthorised
Do not retry. Token is invalid or revoked. Halt Agent 1 immediately, post critical alert to finance Slack channel, and flag for FullSpec team review at support@gofullspec.com.
HubSpot (Agent 1)
Zero deal records returned for the period
Halt Agent 1 without error. Post an informational alert to the finance Slack channel noting the period label and zero-record result. Do not trigger Agent 2. Manual verification required before re-run.
Google Sheets (Agent 1 write)
Write fails due to quota exceeded or network timeout
Retry up to 3 times with 15-second intervals. If all retries fail, halt Agent 1 and post alert. Do not trigger Agent 2. Partial writes must be rolled back by clearing the deal_list sheet before retry.
Google Sheets (Agent 2 read: rate_table)
Missing or malformed commission_rate_pct value for a tier
Flag all deals that map to the affected tier as exceptions with exception_reason 'rate_table_invalid_value'. Do not apply a zero or default rate. Continue processing deals for valid tiers. Post exception list to finance Slack channel before the approval step.
Google Sheets (Agent 2 write: payout_summary)
Write fails or sheet is locked by another user
Retry up to 3 times with 20-second intervals. If all retries fail, halt Agent 2 and post alert. Do not proceed to Agent 3.
Slack (Agent 3: approval message)
chat.postMessage API call fails
Retry up to 3 times with 10-second intervals. If all retries fail, send approval request via email fallback to the manager's address (stored as SLACK_MANAGER_EMAIL in credential store) and post an alert to the finance channel. Log that email fallback was used.
Slack (Agent 3: inbound interaction)
Interaction payload fails signature validation
Reject the payload immediately with HTTP 403. Do not advance the workflow. Log the rejection with raw header values. Post an alert to the finance Slack channel. Require manual re-trigger of the approval message.
Slack (Agent 3: inbound interaction)
No approval or flag response received within 48 hours
Time out the approval step. Post an expiry alert to the finance Slack channel and to SLACK_MANAGER_USER_ID. Halt workflow. Manual re-trigger required after manager responds.
Gusto (Agent 3: payroll write)
Target pay run is already locked or processed
Do not attempt the write. Halt the Gusto step immediately. Post a critical alert to the finance Slack channel with payroll status and run ID. Manual entry into Gusto required. Log the halt.
Gusto (Agent 3: payroll write)
Employee ID not found in GUSTO_EMPLOYEE_ID_MAP
Flag the affected rep as an exception. Do not skip silently. Complete Gusto writes for all matched employees. Post the unmatched rep details to the finance Slack channel for manual resolution.
Gusto (Agent 3: token refresh)
Access token refresh fails
Halt the Gusto step and all downstream steps (Xero, Slack DMs). Post a critical alert. Do not proceed to Xero. Log the OAuth error response in full.
Xero (Agent 3: journal entry)
Journal entry POST fails with 400 Bad Request (e.g. account code not found)
Do not retry. Log the full error response. Post a critical alert to the finance Slack channel with the Xero error message. Manual journal entry required. The Gusto write is not reversed; annotate the run log to indicate Xero step failed.
Xero (Agent 3: journal entry)
Access token expired or refresh fails
Halt the Xero step. Post a critical alert. Do not silently skip journal entry creation. Manual reconciliation required for that pay period.
Slack (Agent 3: rep DMs)
Rep Slack user ID missing from SLACK_USER_ID_MAP
Skip the DM for the unmatched rep without halting the batch. Log the unmatched rep ID. Post a summary of unmatched reps to the finance Slack channel so notification can be handled manually.
Unhandled exceptions must never fail silently. Any error not covered by the scenarios above must be caught by a global error handler in each workflow, logged in full, and surfaced as an alert to the finance Slack channel. The run must be marked as failed in the orchestration platform's run history. Contact support@gofullspec.com if an unhandled error pattern repeats across multiple pay period runs.
Integration and API SpecPage 3 of 3

More documents for this process

Every document generated for Commission & Payout Calculation.

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