FS-DOC-05Technical
Integration and API Spec
Incident and Issue Reporting
[YourCompany.com] · Operations Department · Prepared by FullSpec · [Today's Date]
This document defines the exact integration requirements for every tool in the Incident and Issue Reporting automation. It is written for the FullSpec build team and covers authentication, required scopes, webhook configuration, field mappings, credential store contents, orchestration layout, and failure handling. Nothing in this document is for end-users. All credentials and configuration values must be stored in the central credential store, never hardcoded in workflow logic.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by agent(s)
Google Forms
Structured incident intake trigger
Google OAuth 2.0
Free (Google Workspace or personal)
Agent 1 (Incident Triage)
Google Sheets
Central incident log and status tracker
Google OAuth 2.0
Free (Google Workspace or personal)
Agent 1 and Agent 2
Notion
Per-incident structured record and investigation notes
Notion OAuth 2.0 / Internal Integration Token
Free (Plus recommended for team access)
Agent 1 (Incident Triage)
Slack
Owner assignment notifications and status-chase reminders
Slack OAuth 2.0 (Bot Token)
Free (Pro recommended for message history)
Agent 2 (Notification and Escalation)
Gmail
Reporter acknowledgement emails and updates
Google OAuth 2.0
Free (Google Workspace or personal)
Agent 2 (Notification and Escalation)
PagerDuty
High and critical severity escalation alerts
PagerDuty REST API v2 (API key)
Professional (Events API v2 required)
Agent 2 (Notification and Escalation)
Orchestration layer
Workflow automation platform hosting all agent workflows, credential store, and polling/webhook listeners
Platform-native credential management
As selected during build
All agents
Before you connect anything: sandbox-test every integration using non-production credentials and a dedicated test Google Sheet, test Notion workspace, test Slack channel, and PagerDuty sandbox service. Do not point any workflow at production data until all connections are verified and end-to-end tests pass. See Doc 6 (Test and QA Plan) for test case coverage.
02Per-tool integration detail
Google Forms
Provides the structured incident intake trigger. The connected Google Sheet acts as the live response destination. The orchestration layer polls or watches the sheet for new rows rather than connecting to Forms directly via webhook.
Auth method
Google OAuth 2.0, service account with domain-wide delegation OR user OAuth flow storing refresh token in credential store
Required scopes
https://www.googleapis.com/auth/spreadsheets.readonly (to read new form responses from the connected sheet); https://www.googleapis.com/auth/drive.readonly (if reading form metadata or attachments from Drive)
Trigger setup
Google Forms does not expose a native webhook. The trigger is a poll on the connected Google Sheet (see Sheets entry below). A form-submit Apps Script trigger may optionally be configured to write a flag column, but is not required if polling interval is acceptable.
Required configuration
Form ID stored in credential store. Connected Sheet ID stored in credential store. Column schema must match exactly: Timestamp, Reporter Email, Incident Description, Location, Category Estimate, Severity Estimate, Attachment URL. No field names hardcoded in workflow.
Rate limits
Google Sheets API: 300 read requests/minute per project, 60 requests/minute per user. At ~40 incidents/month, polling every 5 minutes generates well under 9,000 read calls/month. No throttling required.
Constraints
File attachments submitted via Forms are stored in Drive and linked by URL in the sheet. The workflow must not attempt to download attachments inline; pass the Drive URL to the Notion record only.
// Output from Forms (row in connected Sheet)
form_response.timestamp // ISO 8601 string
form_response.reporter_email // string, validated email
form_response.description // string, free text
form_response.location // string
form_response.category_estimate // string, one of predefined options
form_response.severity_estimate // string, one of: Low | Medium | High | Critical
form_response.attachment_url // string, Google Drive URL or empty string
Google Sheets
Serves dual roles: acts as the Forms response destination that triggers the Incident Triage Agent, and as the central incident log written to and updated throughout the lifecycle of each incident.
Auth method
Google OAuth 2.0, same credentials as Google Forms. Reuse the same connection in the credential store.
Required scopes
https://www.googleapis.com/auth/spreadsheets (read and write); https://www.googleapis.com/auth/drive.file (if creating or copying sheet templates programmatically)
Trigger setup
Poll the responses sheet every 5 minutes using the Sheets API spreadsheets.values.get method against the configured range. Track last-processed row index in a persistent variable in the credential store (SHEETS_LAST_ROW_INDEX) to avoid re-processing. On each poll, process only rows where row_index > SHEETS_LAST_ROW_INDEX.
Required configuration
SHEETS_SPREADSHEET_ID stored in credential store. SHEETS_RESPONSES_TAB_NAME stored in credential store (default: 'Form Responses 1'). SHEETS_LOG_TAB_NAME stored in credential store (default: 'Incident Log'). Log schema columns (in order): Incident ID, Timestamp, Reporter Email, Description, Location, Category, Severity Score, Assigned Owner, Deadline, Status, Notion URL, Resolution Notes, Close Timestamp. No column indices hardcoded; resolve by header name at runtime.
Rate limits
300 requests/minute per project. At 40 incidents/month plus resolution updates, peak is well under 50 write operations/day. No throttling required.
Constraints
The log sheet must never be the same tab as the form responses tab. All writes to the log use appendRow for new records and batchUpdate with a row lookup for status updates. Do not overwrite the responses tab.
// Write on new incident (Incident Log tab)
log_row.incident_id // string, format INC-YYYYMMDD-NNN
log_row.timestamp // ISO 8601
log_row.reporter_email // string
log_row.description // string
log_row.location // string
log_row.category // string, output of triage classification
log_row.severity_score // integer 1-4 (1=Low, 2=Medium, 3=High, 4=Critical)
log_row.assigned_owner // string, Slack user ID or email
log_row.deadline // ISO 8601 date
log_row.status // string: Open | In Progress | Resolved | Closed
log_row.notion_url // string, full Notion page URL
log_row.resolution_notes // string, empty on creation
log_row.close_timestamp // string, empty on creation
// Update on resolution
log_row.status // string: Resolved
log_row.resolution_notes // string
log_row.close_timestamp // ISO 8601
Notion
Receives a structured page creation call from the Incident Triage Agent for every new incident. Pages use a fixed database template with defined properties matching the incident schema. Investigation notes and resolution details are appended by owners directly in Notion.
Auth method
Notion Internal Integration Token (preferred for server-side automation). Token stored in credential store as NOTION_API_TOKEN. The integration must be shared with the target database in Notion's sharing settings.
Required scopes
Notion integration capabilities: Read content, Insert content, Update content. No user OAuth flow required for this use case.
Webhook/trigger setup
Notion does not natively emit webhooks. Resolution detection is handled by a scheduled poll of the incident database filtering for pages where Status property equals 'Resolved' AND Sheets_Synced property equals false. Poll interval: 10 minutes. On match, update Sheets and set Sheets_Synced to true.
Required configuration
NOTION_DATABASE_ID stored in credential store (the incidents database). Page template property schema (stored in runbook, not hardcoded): Incident ID (title), Reporter Email (email), Description (rich text), Location (select), Category (select), Severity Score (number), Severity Label (select: Low/Medium/High/Critical), Assigned Owner (person or text), Deadline (date), Status (select: Open/In Progress/Resolved/Closed), Attachment URL (URL), Sheets Row Reference (number), Sheets_Synced (checkbox). All select option values must be pre-created in the database before first run.
Rate limits
Notion API: 3 requests/second average, bursts tolerated. At 40 incidents/month plus polls, peak is under 200 API calls/day. No throttling required.
Constraints
The integration token must not be a user personal token. Use a bot integration. Pages must not be created in the workspace root; always target the configured database ID. Attachment URLs are written as a URL property only; files are not uploaded to Notion.
// Input to Notion API (page create)
notion_page.parent.database_id // NOTION_DATABASE_ID from credential store
notion_page.properties.Incident_ID // title block
notion_page.properties.Reporter_Email // email type
notion_page.properties.Description // rich_text
notion_page.properties.Location // select
notion_page.properties.Category // select
notion_page.properties.Severity_Score // number
notion_page.properties.Severity_Label // select
notion_page.properties.Assigned_Owner // rich_text (Slack ID or name)
notion_page.properties.Deadline // date
notion_page.properties.Status // select: Open
notion_page.properties.Attachment_URL // url
notion_page.properties.Sheets_Row_Ref // number
notion_page.properties.Sheets_Synced // checkbox: false
// Output from Notion (on resolution poll)
notion_page.id // string, Notion page ID
notion_page.url // string, public page URL
notion_page.properties.Status // select: Resolved
notion_page.properties.Sheets_Synced // checkbox: false (filter condition)
notion_page.properties.Resolution_Notes // rich_text
Integration and API SpecPage 1 of 3
FS-DOC-05Technical
Slack
Used by the Notification and Escalation Agent to send owner assignment messages and scheduled status-chase reminders. Messages are sent via the Slack Web API using a bot token. The bot must be invited to the relevant channels or must use direct message (IM) opening.
Auth method
Slack OAuth 2.0, Bot Token (xoxb-). Stored in credential store as SLACK_BOT_TOKEN. Do not use legacy tokens or user tokens.
Required scopes
chat:write (send messages as bot); im:write (open DM channels with users); users:read (resolve user by email to Slack user ID); users:read.email (required alongside users:read for email-based lookup); channels:read (list channels to resolve channel ID at runtime)
Webhook/trigger setup
Outbound only. No inbound webhook or event subscription required for this automation. The bot does not listen for reactions or replies.
Required configuration
SLACK_BOT_TOKEN in credential store. SLACK_INCIDENT_CHANNEL_ID in credential store (fallback notification channel for unresolvable owners). Owner routing table stored in credential store or config sheet (category to Slack user ID mapping). Reminder schedule config: first reminder at deadline minus 24 hours, second at deadline, third at deadline plus 24 hours if still open. All channel IDs resolved by name at deploy time and stored by ID, not name.
Rate limits
Slack Web API Tier 3: 50 requests/minute for chat.postMessage. At 40 incidents/month with up to 3 reminders each, peak is under 160 messages/month. No throttling required.
Constraints
The bot must be added as a member to any channel it posts to. DMs require im:write and an explicit conversations.open call before posting. User ID resolution from email requires users:read.email scope; if not granted, the owner routing table must map category directly to user ID.
// chat.postMessage payload (owner assignment)
slack_message.channel // string, Slack user ID (UXXXXXXXX) for DM
slack_message.text // string, plain text fallback
slack_message.blocks[] // Block Kit: section with incident summary,
// severity label, deadline, Notion URL button
// chat.postMessage payload (status-chase reminder)
slack_message.channel // string, same Slack user ID
slack_message.text // string: 'Reminder: INC-YYYYMMDD-NNN is due [date]'
slack_message.blocks[] // Block Kit: reminder section with Notion linkGmail
Sends automated acknowledgement emails to the incident reporter confirming receipt, the assigned incident ID, the owner name, and the expected resolution timeframe. Uses the Gmail API send method via the authorised Google account.
Auth method
Google OAuth 2.0, same Google account that owns the Forms and Sheets setup, or a dedicated service account with send-as delegation. Stored in credential store as GMAIL_SENDER_ADDRESS and the associated OAuth refresh token.
Required scopes
https://www.googleapis.com/auth/gmail.send (send messages only; do not request broader mail scopes)
Webhook/trigger setup
Outbound send only. No Gmail webhook or Pub/Sub subscription required. The workflow calls gmail.users.messages.send after Slack owner notification is confirmed.
Required configuration
GMAIL_SENDER_ADDRESS in credential store. Email template stored in the credential store or config sheet with placeholders: {{incident_id}}, {{reporter_name}}, {{assigned_owner_name}}, {{severity_label}}, {{deadline}}, {{notion_url}}. Subject line template: 'Incident {{incident_id}} received and assigned'. No template content hardcoded in workflow logic.
Rate limits
Gmail API: 250 quota units per user per second; send costs 100 units. Effective limit: 2 sends/second. At 40 incidents/month the send volume is negligible. No throttling required.
Constraints
The from address must match the authorised account. Do not spoof sender addresses. If the reporter email is missing or malformed, skip send and log a warning to Sheets (do not fail the workflow). HTML body is acceptable but a plain-text fallback must always be included.
// gmail.users.messages.send payload
gmail_message.to // string, form_response.reporter_email
gmail_message.from // string, GMAIL_SENDER_ADDRESS
gmail_message.subject // string, rendered from template
gmail_message.body_html // string, rendered HTML from template
gmail_message.body_text // string, rendered plain text from template
gmail_message.references // empty for first send
PagerDuty
Receives escalation events from the Notification and Escalation Agent when an incident is classified as High (severity score 3) or Critical (severity score 4). Uses the PagerDuty Events API v2 to create an alert on the configured service.
Auth method
PagerDuty Events API v2 integration key (routing key). Stored in credential store as PAGERDUTY_ROUTING_KEY. This is a 32-character hex string associated with the configured PagerDuty service, not the REST API key.
Required scopes
No OAuth scopes. The Events API v2 uses the routing key only. For REST API calls (e.g. listing services during setup), use PAGERDUTY_API_KEY with header 'Authorization: Token token=<key>' stored separately in the credential store.
Webhook/trigger setup
Outbound event send only. POST to https://events.pagerduty.com/v2/enqueue. PagerDuty may optionally be configured to send webhook callbacks to the orchestration layer on acknowledgement or resolution, but this is out of scope for the current build.
Required configuration
PAGERDUTY_ROUTING_KEY in credential store. PAGERDUTY_SERVICE_NAME in credential store (human-readable label for logs). Severity threshold in credential store: PAGERDUTY_TRIGGER_THRESHOLD = 3 (triggers on score >= 3). Dedup key format: incident_id (prevents duplicate alerts for the same incident on retry). Escalation policy configured in PagerDuty console to reach the on-call operations manager.
Rate limits
PagerDuty Events API: no published hard rate limit for Professional tier; practical limit is 1,000 events/minute. At 40 incidents/month with an assumed 20% high/critical rate (~8 PagerDuty events/month), no throttling required.
Constraints
The dedup_key must always be set to the incident_id to prevent duplicate alerts on workflow retry. The payload.summary field must not exceed 1,024 characters. Always send event_action as 'trigger' for new incidents. Do not send PagerDuty alerts for severity scores 1 or 2.
// Events API v2 POST body
pd_event.routing_key // string, PAGERDUTY_ROUTING_KEY
pd_event.event_action // string: 'trigger'
pd_event.dedup_key // string, incident_id (e.g. INC-20240617-001)
pd_event.payload.summary // string: 'INC-20240617-001 [Critical]: {{description_truncated}}'
pd_event.payload.severity // string: 'critical' or 'error' (mapped from score)
pd_event.payload.source // string: 'Incident and Issue Reporting Automation'
pd_event.payload.timestamp // ISO 8601
pd_event.payload.custom_details.incident_id // string
pd_event.payload.custom_details.category // string
pd_event.payload.custom_details.location // string
pd_event.payload.custom_details.reporter_email // string
pd_event.payload.custom_details.notion_url // string
pd_event.links[].href // string, Notion page URL
pd_event.links[].text // string: 'View Notion Record'03Field mappings between tools
The tables below define exact field-level mappings for each agent handoff in the workflow. Monospace field names match the property names used in each tool's API and must be applied verbatim in the orchestration layer.
Handoff 1: Google Forms response to Incident Triage Agent (Sheets row to classification engine)
Source tool
Source field
Destination tool
Destination field
Google Sheets (Forms tab)
`Timestamp`
Triage Agent internal
`form_response.timestamp`
Google Sheets (Forms tab)
`Email Address`
Triage Agent internal
`form_response.reporter_email`
Google Sheets (Forms tab)
`Incident Description`
Triage Agent internal
`form_response.description`
Google Sheets (Forms tab)
`Location`
Triage Agent internal
`form_response.location`
Google Sheets (Forms tab)
`Category (your estimate)`
Triage Agent internal
`form_response.category_estimate`
Google Sheets (Forms tab)
`Severity (your estimate)`
Triage Agent internal
`form_response.severity_estimate`
Google Sheets (Forms tab)
`Attachment (file upload)`
Triage Agent internal
`form_response.attachment_url`
Handoff 2: Incident Triage Agent classification output to Google Sheets Incident Log
Source tool
Source field
Destination tool
Destination field
Triage Agent output
`incident_id`
Google Sheets (Log tab)
`Incident ID`
Triage Agent output
`form_response.timestamp`
Google Sheets (Log tab)
`Timestamp`
Triage Agent output
`form_response.reporter_email`
Google Sheets (Log tab)
`Reporter Email`
Triage Agent output
`form_response.description`
Google Sheets (Log tab)
`Description`
Triage Agent output
`form_response.location`
Google Sheets (Log tab)
`Location`
Triage Agent output
`classification.category`
Google Sheets (Log tab)
`Category`
Triage Agent output
`classification.severity_score`
Google Sheets (Log tab)
`Severity Score`
Triage Agent output
`routing.assigned_owner_email`
Google Sheets (Log tab)
`Assigned Owner`
Triage Agent output
`routing.deadline_iso`
Google Sheets (Log tab)
`Deadline`
Triage Agent output
`'Open'` (literal)
Google Sheets (Log tab)
`Status`
Notion API response
`notion_page.url`
Google Sheets (Log tab)
`Notion URL`
Triage Agent output
`''` (empty)
Google Sheets (Log tab)
`Resolution Notes`
Triage Agent output
`''` (empty)
Google Sheets (Log tab)
`Close Timestamp`
Handoff 3: Incident Triage Agent to Notion (page create)
Source tool
Source field
Destination tool
Destination field
Triage Agent output
`incident_id`
Notion
`properties.Incident_ID` (title)
Triage Agent output
`form_response.reporter_email`
Notion
`properties.Reporter_Email`
Triage Agent output
`form_response.description`
Notion
`properties.Description`
Triage Agent output
`form_response.location`
Notion
`properties.Location`
Triage Agent output
`classification.category`
Notion
`properties.Category`
Triage Agent output
`classification.severity_score`
Notion
`properties.Severity_Score`
Triage Agent output
`classification.severity_label`
Notion
`properties.Severity_Label`
Triage Agent output
`routing.assigned_owner_name`
Notion
`properties.Assigned_Owner`
Triage Agent output
`routing.deadline_iso`
Notion
`properties.Deadline`
Triage Agent output
`'Open'` (literal)
Notion
`properties.Status`
Triage Agent output
`form_response.attachment_url`
Notion
`properties.Attachment_URL`
Sheets API response
`sheets_row_index`
Notion
`properties.Sheets_Row_Ref`
Triage Agent output
`false` (literal)
Notion
`properties.Sheets_Synced`
Handoff 4: Notification and Escalation Agent to Slack, Gmail, and PagerDuty
Source tool
Source field
Destination tool
Destination field
Triage Agent output
`incident_id`
Slack
`slack_message.blocks[].text` (incident reference)
Triage Agent output
`classification.severity_label`
Slack
`slack_message.blocks[].text` (severity badge)
Triage Agent output
`routing.deadline_iso`
Slack
`slack_message.blocks[].text` (deadline display)
Notion API response
`notion_page.url`
Slack
`slack_message.blocks[].accessory.url` (button)
Triage Agent output
`form_response.reporter_email`
Gmail
`gmail_message.to`
Triage Agent output
`incident_id`
Gmail
`gmail_message.subject` (via template)
Triage Agent output
`routing.assigned_owner_name`
Gmail
`gmail_message.body_html` (via placeholder)
Triage Agent output
`routing.deadline_iso`
Gmail
`gmail_message.body_html` (via placeholder)
Notion API response
`notion_page.url`
Gmail
`gmail_message.body_html` (via placeholder)
Triage Agent output
`incident_id`
PagerDuty
`pd_event.dedup_key`
Triage Agent output
`classification.severity_label`
PagerDuty
`pd_event.payload.severity` (mapped: High=error, Critical=critical)
Triage Agent output
`form_response.description`
PagerDuty
`pd_event.payload.summary` (truncated to 1,024 chars)
Notion API response
`notion_page.url`
PagerDuty
`pd_event.links[0].href`
Handoff 5: Notion resolution poll to Google Sheets (status update)
Source tool
Source field
Destination tool
Destination field
Notion
`properties.Sheets_Row_Ref`
Google Sheets (Log tab)
Row index for batchUpdate lookup
Notion
`properties.Status` (Resolved)
Google Sheets (Log tab)
`Status`
Notion
`properties.Resolution_Notes`
Google Sheets (Log tab)
`Resolution Notes`
Orchestration layer
`now()` ISO 8601
Google Sheets (Log tab)
`Close Timestamp`
Integration and API SpecPage 2 of 3
FS-DOC-05Technical
04Build stack and orchestration
Orchestration layout
Two discrete workflows, one per agent. Agent 1: Incident Triage Workflow. Agent 2: Notification and Escalation Workflow. Both workflows share a single credential store. No cross-workflow direct calls; Agent 2 is triggered by a watch on the Sheets incident log for rows where Status = 'Open' AND Notion_URL is populated, confirming Agent 1 completed successfully.
Agent 1 trigger mechanism
Scheduled poll. Interval: every 5 minutes. Method: read Google Sheets responses tab via Sheets API spreadsheets.values.get. Compare current last row index against SHEETS_LAST_ROW_INDEX stored in credential store. Process only net-new rows. Update SHEETS_LAST_ROW_INDEX on completion.
Agent 2 trigger mechanism
Scheduled poll. Interval: every 5 minutes. Method: read Sheets incident log for rows where Status = 'Open' AND Notion_URL is non-empty AND Notified flag column is false. Process each matched row, send notifications, set Notified = true. Reminder scheduler: separate scheduled poll every 60 minutes checking deadline proximity against configured thresholds.
Notion resolution poll
Scheduled poll every 10 minutes. Method: Notion database query filtering Status = Resolved AND Sheets_Synced = false. On match, update Sheets row and set Sheets_Synced = true in Notion.
Webhook signature validation
No inbound webhooks in this automation. All triggers are outbound polls. If a future iteration introduces a Slack event subscription or PagerDuty webhook callback, HMAC-SHA256 signature validation must be implemented before any payload is processed.
Credential store
All secrets and configuration values stored in the platform-native encrypted credential store. No credentials in workflow node configuration fields. Reference by variable name only (see code block below).
Error log destination
All caught exceptions write a structured error record to a dedicated 'Automation Errors' tab in the Sheets workbook. Fields: timestamp, workflow name, step name, error message, incident_id (if available), retry count.
Credential store contents (all entries required before first run)
// Google (shared across Forms, Sheets, Gmail)
GOOGLE_OAUTH_CLIENT_ID // string, from Google Cloud Console
GOOGLE_OAUTH_CLIENT_SECRET // string, from Google Cloud Console
GOOGLE_OAUTH_REFRESH_TOKEN // string, obtained during OAuth flow
GMAIL_SENDER_ADDRESS // string, e.g. incidents@[YourCompany.com]
// Google Sheets
SHEETS_SPREADSHEET_ID // string, from Sheet URL
SHEETS_RESPONSES_TAB_NAME // string, default: 'Form Responses 1'
SHEETS_LOG_TAB_NAME // string, default: 'Incident Log'
SHEETS_LAST_ROW_INDEX // integer, updated by workflow on each poll run
SHEETS_NOTIFIED_COL_NAME // string, default: 'Notified'
// Notion
NOTION_API_TOKEN // string, internal integration token
NOTION_DATABASE_ID // string, from Notion database URL
// Slack
SLACK_BOT_TOKEN // string, xoxb- prefixed bot token
SLACK_INCIDENT_CHANNEL_ID // string, fallback channel ID
// PagerDuty
PAGERDUTY_ROUTING_KEY // string, Events API v2 integration key
PAGERDUTY_API_KEY // string, REST API key (setup/admin use only)
PAGERDUTY_TRIGGER_THRESHOLD // integer, default: 3
PAGERDUTY_SERVICE_NAME // string, human-readable label for logs
// Triage configuration
SEVERITY_RUBRIC_VERSION // string, e.g. 'v1.2' (for audit reference)
OWNER_ROUTING_TABLE // JSON object: { category: { slack_id, email, name } }
REMINDER_SCHEDULE_HOURS // JSON array: [-24, 0, 24] (relative to deadline)
// Email template
GMAIL_SUBJECT_TEMPLATE // string with {{incident_id}} placeholder
GMAIL_BODY_HTML_TEMPLATE // string with all required placeholders
GMAIL_BODY_TEXT_TEMPLATE // string, plain text versionSHEETS_LAST_ROW_INDEX is a mutable value updated by Agent 1 on every successful poll. If the workflow platform does not support persistent mutable variables natively, store this value in a dedicated single-cell 'Config' tab in the Sheets workbook and read/write it via API on each run.
05Error handling and retry logic
Every integration point has a defined failure behaviour. Unhandled exceptions must never fail silently. All errors are caught, logged to the Automation Errors tab in Google Sheets, and where appropriate an alert is sent to SLACK_INCIDENT_CHANNEL_ID flagging a workflow fault. Retry logic uses exponential backoff unless stated otherwise.
Integration
Scenario
Required behaviour
Google Sheets (poll)
API returns 429 Too Many Requests
Retry with exponential backoff: wait 30 s, 60 s, 120 s (max 3 retries). If still failing after 3 retries, log error to Automation Errors tab and skip poll cycle. Do not advance SHEETS_LAST_ROW_INDEX. Alert ops channel.
Google Sheets (poll)
Spreadsheet ID not found or permission denied (403/404)
Do not retry. Log critical error to Automation Errors tab. Alert ops channel immediately. Halt workflow until credential is corrected.
Notion (page create)
API returns 409 Conflict (duplicate incident_id)
Log warning, skip Notion create, retrieve existing page URL using database query filter on Incident_ID title. Proceed with existing URL. Do not create duplicate page.
Notion (page create)
API returns 400 Bad Request (invalid property value, e.g. select option not pre-created)
Retry once after 10 s. If still failing, write incident to Sheets log with Notion_URL = 'NOTION_CREATE_FAILED'. Alert ops channel with property name causing failure. Do not block Slack or Gmail notifications.
Notion (resolution poll)
API returns 503 Service Unavailable
Retry with backoff: 30 s, 60 s, 120 s. If all retries fail, defer sync to next poll cycle (10 minutes). Do not mark Sheets_Synced = true until a successful write to Sheets is confirmed.
Slack (chat.postMessage)
User ID cannot be resolved from owner routing table (user not found or deactivated)
Fall back to posting to SLACK_INCIDENT_CHANNEL_ID with owner name in message text. Log warning with category and attempted user ID. Do not halt workflow.
Slack (chat.postMessage)
API returns 429 rate limit
Retry after Retry-After header value (or 60 s default). Max 3 retries. If still failing, log error and continue to Gmail step. Do not block Gmail send.
Gmail (message send)
Reporter email is missing or fails RFC 5322 validation
Skip Gmail send entirely. Log warning to Automation Errors tab with incident_id. Do not fail the workflow. Ops channel alert not required for this scenario.
Gmail (message send)
OAuth token expired or refresh fails
Attempt token refresh once. If refresh fails, log critical error to Automation Errors tab and alert ops channel. Halt Gmail step only; continue all other steps in the run.
PagerDuty (event trigger)
Events API returns non-2xx (e.g. 400 invalid routing key, 429 rate limit)
Retry up to 3 times with 30 s backoff. If all retries fail, post a manual escalation alert directly to SLACK_INCIDENT_CHANNEL_ID with full incident details and severity label. Log error to Automation Errors tab. Never allow a High or Critical incident to go unescalated.
PagerDuty (event trigger)
Duplicate dedup_key received (retry sent same incident_id)
PagerDuty deduplication handles this natively. No additional workflow logic required. Log as informational only.
Triage Agent (classification)
Form response missing required fields (description or category_estimate empty)
Assign severity_score = 2 (Medium) as safe default. Set category = 'Unclassified'. Flag the Sheets log row and Notion page with a 'NEEDS_REVIEW' tag. Send owner notification to the fallback ops channel owner defined in OWNER_ROUTING_TABLE under key 'Unclassified'. Do not skip record creation.
Unhandled exceptions must never fail silently. Any error not covered by the table above must be caught by a global error handler, written to the Automation Errors tab with full stack context, and trigger a Slack alert to the ops channel. The record being processed must be preserved and flagged for manual review, never discarded.
Integration and API SpecPage 3 of 3