Back to Budget vs Actuals Reporting

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

Budget vs Actuals Reporting

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

This document is the authoritative technical reference for every tool-to-tool integration in the Budget vs Actuals Reporting automation. It covers the full tool inventory, per-tool authentication and scope requirements, exact field mappings across agent handoffs, orchestration layout, credential store contents, and defined error handling behaviour for every integration point. FullSpec uses this specification to build, configure, and validate all connections. No credentials should be hardcoded into workflow steps; every secret must reside in the shared credential store described in Section 04.

01Tool inventory

Tool
Role in automation
Auth method
Min plan required
Used by agents
QuickBooks Online
Source of closed-period P&L actuals via API
OAuth 2.0 (authorization code flow)
Essentials or above (API access required)
Agent 1 (Actuals Sync)
Google Sheets
Budget template store, variance calculation surface, and commentary staging area
OAuth 2.0 via Google service account (JWT)
Google Workspace or free Google account with Sheets API enabled
Agents 1, 2, 3
Google Drive
Published report storage and stakeholder sharing
OAuth 2.0 via same Google service account as Sheets
Google Workspace or free Google account with Drive API enabled
Agent 3 (Report Distribution)
Slack
Variance alerts to department heads and stakeholder distribution notifications
OAuth 2.0 (Slack app bot token, scopes defined per-tool below)
Free tier or above (Incoming Webhooks and Bot API available on all tiers)
Agents 2, 3
Orchestration layer
Scheduling, agent sequencing, credential management, retry logic, and error alerting
Internal platform credential store; no external OAuth
Workflow automation platform subscription ($80/month as per tooling plan)
All agents
Before you connect anything: all four external tool connections (QuickBooks, Google Sheets, Google Drive, Slack) must be authenticated and smoke-tested against sandbox or developer accounts before any production credentials are entered. Use a prior-period QuickBooks sandbox company file, a copy of the budget template in a test Google account, a dedicated test Slack workspace, and a sandboxed Drive folder. Only after each connection returns expected data in the test environment should the equivalent production credential be added to the credential store.

02Per-tool integration detail

QuickBooks Online

Provides the closed-period Profit and Loss report via the Reports API. The Actuals Sync Agent calls this endpoint on schedule each month-end, parses account-level rows, and passes figures to the Google Sheets write step. The connection uses OAuth 2.0 with offline access so the token can be refreshed without user interaction.

Auth method
OAuth 2.0 authorization code flow. App registered at developer.intuit.com. Client ID and Client Secret stored in credential store (keys: QB_CLIENT_ID, QB_CLIENT_SECRET). Access token (QB_ACCESS_TOKEN) and refresh token (QB_REFRESH_TOKEN) stored separately and rotated automatically on each 60-minute expiry.
Required scopes
com.intuit.quickbooks.accounting (read-only reporting access is sufficient; do not request write or payment scopes)
Webhook / trigger setup
No inbound webhook from QuickBooks is required. The orchestration layer fires on a scheduled date trigger (configurable monthly cadence). The agent then initiates an outbound REST call to the Reports API. If a webhook-based period-close signal is available in future, it would use the QuickBooks webhooks endpoint at https://developer.intuit.com/app/developer/qbo/docs/develop/webhooks, validated via the Intuit-Signature header using the verifier token stored as QB_WEBHOOK_VERIFIER.
Required configuration
Realm ID (QuickBooks company identifier, stored as QB_REALM_ID in credential store). Reporting period parameters: start_date and end_date derived at runtime from the trigger date. Summarize columns by: Account. Report basis: Accrual (confirm with finance manager; stored as QB_REPORT_BASIS). All IDs stored in credential store, never hardcoded in workflow steps.
Key API endpoint
GET https://quickbooks.api.intuit.com/v3/company/{QB_REALM_ID}/reports/ProfitAndLoss?start_date={start_date}&end_date={end_date}&summarize_column_by=Account&accounting_method={QB_REPORT_BASIS}
Rate limits
QuickBooks Online API: 500 requests per minute per company, 10 concurrent requests. This automation makes 1 to 3 API calls per monthly run (report fetch plus optional token refresh). Throttling is not required at current volume (1 run/month). However, the retry handler must observe a 2-second minimum delay between retries to avoid contributing to burst limits during error recovery.
Constraints
Refresh tokens expire after 100 days of inactivity. The orchestration layer must store the last-refreshed timestamp and trigger a re-authorisation alert (via Slack to the finance manager) if the token is within 10 days of expiry. The API returns a JSON structure with nested Rows and Columns arrays; the parser must handle both Summary and Detail row types and skip SubTotalData rows to avoid double-counting.
// Outbound request
GET /v3/company/{QB_REALM_ID}/reports/ProfitAndLoss
  Headers: Authorization: Bearer {QB_ACCESS_TOKEN}
           Accept: application/json
  Params:  start_date, end_date, summarize_column_by=Account, accounting_method

// Response shape (simplified)
{
  'Header': { 'ReportName': 'ProfitAndLoss', 'StartPeriod': '...', 'EndPeriod': '...' },
  'Rows': {
    'Row': [
      { 'type': 'Section', 'group': 'Income', 'Rows': { 'Row': [ ... ] } },
      { 'type': 'Section', 'group': 'Expenses', 'Rows': { 'Row': [ ... ] } }
    ]
  }
}
Google Sheets

The budget template lives in a designated Google Sheet. The Actuals Sync Agent writes fetched actuals into the sheet, the Variance Analysis Agent reads from it to compute variances and pre-populate commentary, and the Report Distribution Agent reads the finalised sheet to package the report. Access is via a service account so no user-level OAuth prompt is required during automated runs.

Auth method
Google service account (JWT-based). Service account JSON key stored as GOOGLE_SA_KEY in credential store. The service account email must be granted Editor access to the budget spreadsheet and the Drive folder. Never share the service account JSON key in plain text outside the credential store.
Required scopes
https://www.googleapis.com/auth/spreadsheets (read and write to Sheets), https://www.googleapis.com/auth/drive.file (create and update files in Drive; used by Report Distribution Agent)
Webhook / trigger setup
No inbound webhook from Google Sheets. The Variance Analysis Agent is triggered by a completion event from the Actuals Sync Agent within the orchestration layer, not by a Sheets-native trigger. The finance manager approval gate is implemented as a polling check against a designated approval cell (e.g. APPROVAL_CELL address stored as SHEETS_APPROVAL_CELL_REF) rather than an Apps Script trigger, to keep all logic inside the orchestration layer.
Required configuration
Spreadsheet ID stored as SHEETS_BUDGET_SPREADSHEET_ID. Actuals column range stored as SHEETS_ACTUALS_RANGE (e.g. 'Actuals!B2:B55'). Budget column range stored as SHEETS_BUDGET_RANGE (e.g. 'Budget!B2:B55'). Commentary column range stored as SHEETS_COMMENTARY_RANGE (e.g. 'Commentary!C2:C55'). Approval cell reference stored as SHEETS_APPROVAL_CELL_REF. Account mapping table sheet name stored as SHEETS_MAPPING_TAB. Variance threshold percentage stored as VARIANCE_THRESHOLD_PCT. All values stored in credential store, not hardcoded.
Sheet structure requirement
The budget template must have: row 1 as a frozen header row (never overwritten by automation); a dedicated account code column (column A by convention, containing codes that match QB account names after mapping); an actuals column (configurable via SHEETS_ACTUALS_RANGE); a variance formula column (pre-built, not overwritten by automation); a commentary column; and an approval cell outside the data range. The account mapping tab maps QB account names to budget row numbers.
Rate limits
Google Sheets API v4: 300 requests per minute per project, 60 requests per minute per user. A single monthly run generates approximately 4 to 6 API calls (one batch read, one batch write for actuals, one read for variance pass, one write for commentary, one read for approval status). Well within limits. No throttling required at current volume.
Constraints
Batch write operations must use the batchUpdate method with valueInputOption set to USER_ENTERED to preserve formula evaluation. The write range must never overlap row 1 (headers). If the sheet has named ranges, prefer named range references over A1 notation to make the integration resilient to column insertions. The service account must not have Owner-level Drive permissions; Editor is sufficient and follows least-privilege.
// Read actuals range
GET https://sheets.googleapis.com/v4/spreadsheets/{SHEETS_BUDGET_SPREADSHEET_ID}/values/{SHEETS_ACTUALS_RANGE}

// Batch write actuals
PUT https://sheets.googleapis.com/v4/spreadsheets/{SHEETS_BUDGET_SPREADSHEET_ID}/values/{SHEETS_ACTUALS_RANGE}
  Body: { 'range': SHEETS_ACTUALS_RANGE, 'values': [[v1],[v2],...], 'majorDimension': 'COLUMNS' }
  Params: valueInputOption=USER_ENTERED

// Write commentary
PUT https://sheets.googleapis.com/v4/spreadsheets/{SHEETS_BUDGET_SPREADSHEET_ID}/values/{SHEETS_COMMENTARY_RANGE}
  Body: { 'range': SHEETS_COMMENTARY_RANGE, 'values': [[c1],[c2],...] }

// Poll approval cell
GET https://sheets.googleapis.com/v4/spreadsheets/{SHEETS_BUDGET_SPREADSHEET_ID}/values/{SHEETS_APPROVAL_CELL_REF}
Integration and API SpecPage 1 of 3
FS-DOC-05Technical
Google Drive

The Report Distribution Agent saves the finalised report to a designated Google Drive folder with a date-stamped filename and applies sharing permissions so all configured stakeholders can access it via link. The same service account used for Google Sheets handles Drive operations.

Auth method
Same Google service account as Sheets (GOOGLE_SA_KEY). No separate credential required. The service account must have at least Contributor access to the target Drive folder.
Required scopes
https://www.googleapis.com/auth/drive.file (sufficient for creating and updating files created by the service account in the target folder)
Webhook / trigger setup
No inbound webhook. The Report Distribution Agent is triggered by the approval gate passing within the orchestration layer, not by a Drive event.
Required configuration
Target Drive folder ID stored as DRIVE_REPORT_FOLDER_ID. File naming convention template stored as DRIVE_FILE_NAME_TEMPLATE (e.g. 'BudgetVsActuals_{YYYY}-{MM}_v{version}.pdf'). Stakeholder email list stored as DRIVE_STAKEHOLDER_EMAILS (comma-separated). Export format: PDF via Sheets export endpoint. Sharing permission type: reader, with link. All values in credential store.
Rate limits
Google Drive API v3: 1,000 requests per 100 seconds per user. This automation creates 1 file per monthly run. No throttling required.
Constraints
Use the Sheets export-as-PDF endpoint rather than a third-party PDF converter to avoid file format drift. The file must be created in the configured folder, not in the service account's root Drive. Do not set sharing to 'public on the web'; use 'anyone with the link' scoped to reader only, or restrict to the explicit stakeholder email list depending on company data policy.
// Export sheet as PDF and upload to Drive folder
GET https://docs.google.com/spreadsheets/d/{SHEETS_BUDGET_SPREADSHEET_ID}/export
  Params: format=pdf&gid={SHEET_GID}&portrait=true&fitw=true
  -> binary PDF content

POST https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart
  Metadata: { 'name': '{DRIVE_FILE_NAME_TEMPLATE}', 'parents': ['{DRIVE_REPORT_FOLDER_ID}'] }
  Body: multipart/related with metadata + PDF binary
  -> returns { 'id': '{new_file_id}' }

// Set sharing permissions
POST https://www.googleapis.com/drive/v3/files/{new_file_id}/permissions
  Body: { 'type': 'anyone', 'role': 'reader' }
Slack

Slack is used at two points: the Variance Analysis Agent posts targeted alerts to department heads requesting variance explanations, and the Report Distribution Agent posts a final notification with the Drive link to the stakeholder channel. Both use a single Slack bot app with a bot token.

Auth method
Slack OAuth 2.0, bot token (xoxb-...). App created in the Slack API console at api.slack.com/apps. Bot token stored as SLACK_BOT_TOKEN in credential store. No user token required.
Required scopes
chat:write (post messages to channels and DMs), chat:write.public (post to channels the bot has not joined), users:read (resolve department head user IDs from email), users:read.email (required for user lookup by email address), channels:read (list channels to validate configured channel IDs at startup)
Webhook / trigger setup
Outbound only for variance alerts and distribution notifications. If Slack reply collection is implemented to capture department head responses: an inbound Event API subscription is required, with the events_api_url pointing to the orchestration layer's inbound webhook endpoint. Event types required: message.channels, message.im. The request signing secret must be verified on every inbound payload using the X-Slack-Signature header and the SLACK_SIGNING_SECRET stored in the credential store.
Required configuration
Finance channel ID stored as SLACK_FINANCE_CHANNEL_ID. Department head user IDs or email-to-ID mapping stored as SLACK_DEPT_HEAD_MAP (JSON object keyed by cost-centre code). Variance alert message template ID or text stored as SLACK_VARIANCE_TEMPLATE. Distribution notification template stored as SLACK_DIST_TEMPLATE. Reply collection window in hours stored as SLACK_REPLY_WINDOW_HOURS. All in credential store.
Rate limits
Slack Web API: 1 message per second per method by default (Tier 3 methods such as chat.postMessage allow up to 50 requests per minute). With up to 50 cost-centre lines, a worst case run might post 20 to 30 individual DMs. At 1/second, completion takes under 30 seconds. No special throttling logic required, but the message-sending loop should include a 1.1-second delay between DMs to stay safely within tier limits.
Constraints
Bot must be invited to SLACK_FINANCE_CHANNEL_ID before first run. Department head user IDs must be pre-resolved and stored; do not resolve at runtime to avoid rate limit pressure on users:read. Message blocks must not exceed 3,000 characters per block. If the Slack app is on the free tier, message history beyond 90 days is not searchable, which is acceptable for this use case.
// Post variance alert DM to department head
POST https://slack.com/api/chat.postMessage
  Headers: Authorization: Bearer {SLACK_BOT_TOKEN}
  Body: {
    'channel': '{dept_head_user_id}',
    'text': 'Variance alert for {cost_centre}: {line_name} is {variance_pct}% over budget.',
    'blocks': [ ... Block Kit layout ... ]
  }

// Post distribution notification to finance channel
POST https://slack.com/api/chat.postMessage
  Body: {
    'channel': '{SLACK_FINANCE_CHANNEL_ID}',
    'text': 'Budget vs Actuals report for {period} is ready: {drive_file_link}',
    'blocks': [ ... summary block with link ... ]
  }

03Field mappings between tools

The following tables define the exact field mappings at each agent handoff. Field names shown in monospace reflect the actual key names in API responses and spreadsheet column references as configured in the credential store. Any deviation from these names requires an update to both the mapping table and the credential store configuration.

Handoff 1: Actuals Sync Agent, QuickBooks to Google Sheets

Source tool
Source field
Destination tool
Destination field
QuickBooks
`Rows.Row[].ColData[0].value` (account name)
Google Sheets mapping tab
`account_name` (column A, SHEETS_MAPPING_TAB)
QuickBooks
`Rows.Row[].ColData[1].value` (period amount)
Google Sheets actuals column
`actual_amount` (SHEETS_ACTUALS_RANGE, row index from mapping)
QuickBooks
`Header.StartPeriod`
Google Sheets header row
`period_start` (SHEETS_PERIOD_HEADER_CELL)
QuickBooks
`Header.EndPeriod`
Google Sheets header row
`period_end` (SHEETS_PERIOD_HEADER_CELL_END)
QuickBooks
`Header.Currency`
Google Sheets metadata cell
`report_currency` (SHEETS_CURRENCY_CELL)
Account mapping table
`budget_row_index` (resolved from `account_name`)
Google Sheets actuals column
Row offset for batch write into SHEETS_ACTUALS_RANGE

Handoff 2: Variance Analysis Agent, Google Sheets internal read/write

Source tool
Source field
Destination tool
Destination field
Google Sheets
`budget_amount` (SHEETS_BUDGET_RANGE, per row)
Google Sheets variance calculation
`variance_dollar` = `actual_amount` - `budget_amount`
Google Sheets
`actual_amount` (SHEETS_ACTUALS_RANGE, per row)
Google Sheets variance calculation
`variance_pct` = (`variance_dollar` / `budget_amount`) * 100
Google Sheets
`variance_pct`
Google Sheets flag column
`flagged` = TRUE if ABS(`variance_pct`) >= VARIANCE_THRESHOLD_PCT
Google Sheets
`line_name` (column A of data tab)
Slack DM payload
`line_name` in `blocks[].text`
Google Sheets
`variance_pct`, `variance_dollar`
Slack DM payload
`variance_pct`, `variance_dollar` in `blocks[].text`
Google Sheets
`cost_centre_code` (column B of data tab)
SLACK_DEPT_HEAD_MAP lookup
`dept_head_user_id` resolved for DM routing

Handoff 3: Report Distribution Agent, Google Sheets and Google Drive to Slack

Source tool
Source field
Destination tool
Destination field
Google Sheets
`period_start`, `period_end` (header cells)
Google Drive file metadata
`name` field in DRIVE_FILE_NAME_TEMPLATE substitution
Google Sheets
Full sheet export (PDF binary)
Google Drive
`file_body` (multipart upload)
Google Drive
`id` (new file ID from upload response)
Slack notification
`drive_file_link` = `https://drive.google.com/file/d/{id}/view`
Google Sheets
`total_flagged_lines` (count of flagged rows)
Slack notification
`flagged_count` in `blocks[].text`
Google Sheets
`commentary_pending_lines` (lines with empty commentary)
Slack notification
`pending_commentary_count` in `blocks[].text`
Credential store
DRIVE_STAKEHOLDER_EMAILS
Google Drive permissions
`emailAddress` in permissions body (if restricted sharing)
Integration and API SpecPage 2 of 3
FS-DOC-05Technical

04Build stack and orchestration

Orchestration layout
Three discrete workflows, one per agent (Actuals Sync Agent, Variance Analysis Agent, Report Distribution Agent). Each workflow is a self-contained unit with its own trigger, steps, and error handler. Agents are chained by completion events: Agent 1 emits a success event that triggers Agent 2; Agent 2 emits a success event that triggers Agent 3 after the approval gate passes. A shared credential store is the single source of truth for all secrets and configuration values; no credentials are embedded in workflow step definitions.
Agent 1 trigger mechanism
Scheduled poll. The orchestration platform evaluates a cron-style schedule configured to fire on the first business day after the period-close date each month (exact date stored as TRIGGER_PERIOD_CLOSE_DAY in credential store). No inbound webhook from QuickBooks. After firing, the workflow calls the QuickBooks API and proceeds if the report returns data for the expected period. If the QuickBooks API returns an empty or partial response, the workflow halts and sends an alert before any write to Sheets occurs.
Agent 2 trigger mechanism
Internal completion event from Agent 1. The orchestration layer passes the run ID and a confirmation that the Sheets write succeeded. No external webhook. Agent 2 then reads the sheet, runs variance logic, and posts Slack DMs. The Slack reply collection window (SLACK_REPLY_WINDOW_HOURS) is enforced by a scheduled delay node that waits before triggering the commentary pre-population step.
Agent 3 trigger mechanism
Approval gate poll. The orchestration platform polls SHEETS_APPROVAL_CELL_REF every 15 minutes (configurable via APPROVAL_POLL_INTERVAL_MINS in credential store). When the cell value equals 'APPROVED' (case-insensitive), Agent 3 fires. If no approval is recorded within APPROVAL_TIMEOUT_HOURS, an escalation Slack message is posted to SLACK_FINANCE_CHANNEL_ID. Signature validation is not applicable to this internal poll mechanism.
Inbound Slack webhook signature validation
If the Slack Event API is enabled for reply collection: every inbound POST to the orchestration layer's events endpoint must be verified. Compute HMAC-SHA256 of 'v0:{slack_request_timestamp}:{raw_body}' using SLACK_SIGNING_SECRET. Compare to the value in X-Slack-Signature header (prefix 'v0='). Reject any request where the timestamp is more than 300 seconds old, to prevent replay attacks.
Shared credential store
All keys listed in the code block below. No key may be duplicated in workflow step configuration. Key rotation for OAuth tokens is handled automatically by the orchestration platform's token refresh module. Non-OAuth secrets (service account key, bot token) are rotated manually and the updated value is written to the credential store only.
Credential store contents (all keys required before first run)
// QuickBooks Online
QB_CLIENT_ID                  = '<QuickBooks app client ID>'
QB_CLIENT_SECRET              = '<QuickBooks app client secret>'
QB_ACCESS_TOKEN               = '<OAuth access token, auto-refreshed>'
QB_REFRESH_TOKEN              = '<OAuth refresh token, 100-day expiry>'
QB_REALM_ID                   = '<QuickBooks company Realm ID>'
QB_REPORT_BASIS               = 'Accrual'   // or 'Cash'; confirm with finance manager
QB_TOKEN_LAST_REFRESHED       = '<ISO8601 timestamp>'
QB_WEBHOOK_VERIFIER           = '<Intuit webhook verifier token, if webhooks used>'

// Google (Sheets + Drive, shared service account)
GOOGLE_SA_KEY                 = '<Full JSON key for Google service account>'
SHEETS_BUDGET_SPREADSHEET_ID  = '<Google Sheet ID from URL>'
SHEETS_ACTUALS_RANGE          = 'Actuals!B2:B55'   // adjust to match actual sheet
SHEETS_BUDGET_RANGE           = 'Budget!B2:B55'
SHEETS_COMMENTARY_RANGE       = 'Commentary!C2:C55'
SHEETS_APPROVAL_CELL_REF      = 'Approval!B1'
SHEETS_MAPPING_TAB            = 'AccountMapping'
SHEETS_PERIOD_HEADER_CELL     = 'Summary!C1'
SHEETS_PERIOD_HEADER_CELL_END = 'Summary!D1'
SHEETS_CURRENCY_CELL          = 'Summary!A3'
VARIANCE_THRESHOLD_PCT        = 10   // percent; flagged if ABS(variance) >= this

// Google Drive
DRIVE_REPORT_FOLDER_ID        = '<Google Drive folder ID>'
DRIVE_FILE_NAME_TEMPLATE      = 'BudgetVsActuals_{YYYY}-{MM}_v{version}.pdf'
DRIVE_STAKEHOLDER_EMAILS      = 'ceo@example.com,ops@example.com'  // comma-separated

// Slack
SLACK_BOT_TOKEN               = 'xoxb-<bot token>'
SLACK_SIGNING_SECRET          = '<Slack app signing secret>'
SLACK_FINANCE_CHANNEL_ID      = 'C0123456789'   // #finance channel ID
SLACK_DEPT_HEAD_MAP           = '{"OPEX":"U0123","MKTG":"U0456"}'  // JSON
SLACK_REPLY_WINDOW_HOURS      = 24

// Orchestration config
TRIGGER_PERIOD_CLOSE_DAY      = 1   // day of month; adjust if close day varies
APPROVAL_POLL_INTERVAL_MINS   = 15
APPROVAL_TIMEOUT_HOURS        = 48
ALERT_ESCALATION_EMAIL        = 'support@gofullspec.com'   // fallback alert target
The GOOGLE_SA_KEY value is a multi-line JSON object. Store it as a single escaped string or use the credential store's 'secure JSON' field type if available. Never log or echo this key in workflow execution history. Rotate the service account key every 90 days and update the credential store before the old key is revoked.

05Error handling and retry logic

Every integration point has a defined failure behaviour. Unhandled exceptions must never fail silently. Any error not covered by a specific handler below must be caught by a global fallback that logs the full error payload and posts an alert to SLACK_FINANCE_CHANNEL_ID and ALERT_ESCALATION_EMAIL before halting the run.

Integration
Scenario
Required behaviour
QuickBooks API, token fetch
Access token expired (401 Unauthorized)
Automatic: attempt token refresh using QB_REFRESH_TOKEN before retrying the original request. If refresh also fails, halt Agent 1, post Slack alert to finance channel with token re-auth instructions, and do not proceed to Sheets write.
QuickBooks API, P&L report fetch
API returns HTTP 429 (rate limit exceeded)
Retry with exponential backoff: wait 2 seconds, then 4 seconds, then 8 seconds. Maximum 3 retries. If all retries fail, halt the run and send escalation alert. Do not silently skip.
QuickBooks API, P&L report fetch
Report returns empty Rows array or period does not match expected dates
Halt Agent 1 immediately. Do not write to Sheets. Post alert: 'QuickBooks P&L returned no data for {period}. Manual verification required.' Log expected vs returned period values.
Google Sheets, actuals write
Batch write fails (403 Forbidden or service account permission error)
Retry once after 5 seconds. If retry fails, halt Agent 1 and post alert. Do not attempt a partial write. A partial actuals column is worse than no write because it would produce silent variance calculation errors.
Google Sheets, account mapping
QuickBooks account name not found in SHEETS_MAPPING_TAB
Flag the unmapped account in a dedicated 'Unmapped Accounts' range on the mapping tab. Continue writing all mapped accounts. Post a Slack alert listing unmapped accounts so the finance manager can add them to the mapping table before the variance step runs.
Google Sheets, approval gate poll
Approval cell not set to APPROVED within APPROVAL_TIMEOUT_HOURS
Post escalation message to SLACK_FINANCE_CHANNEL_ID: 'Report for {period} is awaiting approval. Please review and set the approval cell to APPROVED.' Continue polling. Do not auto-approve or bypass the gate.
Slack, variance DM to department head
User ID not found in SLACK_DEPT_HEAD_MAP for a cost-centre code
Skip the DM for that cost centre. Log the missing mapping. Post a single consolidated alert to SLACK_FINANCE_CHANNEL_ID listing all cost-centre codes with no mapped user. Do not silently drop the alert.
Slack, variance DM or distribution notification
API returns HTTP 429 or Tier rate limit error
Pause message loop for 60 seconds, then retry the failed message. If retry fails after 60 seconds, log the failed message payload and continue to the next message. Post a summary of failed messages to the finance channel at the end of the run.
Slack, inbound reply collection (Event API)
Inbound webhook payload fails signature verification
Reject the request with HTTP 400. Log the rejection with the raw X-Slack-Signature and computed HMAC for audit. Do not process the payload. Do not silently drop it.
Google Drive, file upload
Upload fails (network error or 500 from Drive API)
Retry up to 3 times with 5-second intervals using resumable upload if file is over 5 MB; otherwise retry multipart upload. If all retries fail, halt Agent 3 and post alert. Do not post the Slack distribution notification until a Drive file ID is confirmed.
Google Drive, permissions set
Permission POST returns error (e.g. 403 or Drive sharing policy restriction)
Log the error and post an alert: 'Report file uploaded but sharing permissions could not be set. Manual sharing required.' Include the Drive file ID in the alert so the finance manager can share manually. Do not suppress this error.
Orchestration layer, global unhandled exception
Any step throws an error not matched by a specific handler above
Catch all unhandled exceptions at workflow level. Log full error stack, step name, and run ID. Post alert to SLACK_FINANCE_CHANNEL_ID and ALERT_ESCALATION_EMAIL with step context. Mark the run as FAILED in the orchestration audit log. Never allow silent failure.
For support on any integration failure or credential issue, contact the FullSpec team at support@gofullspec.com. Include the run ID, the step name from the orchestration audit log, and the error message text. FullSpec monitors production runs during the first two monthly cycles after go-live and will respond to alerts within one business day.
Integration and API SpecPage 3 of 3

More documents for this process

Every document generated for Budget vs Actuals Reporting.

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