FS-DOC-05Technical
Integration and API Spec
OKR and Goal Tracking Automation
[YourCompany.com] · Management Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for every integration point in the OKR and Goal Tracking automation. It covers authentication methods, required permission scopes, webhook configurations, field mappings between tools, credential store contents, orchestration layout, and failure behaviour for each integration. The FullSpec team uses this specification during build and configuration; it also serves as the primary reference during QA and any future maintenance work.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by agent(s)
Slack
Update request delivery, timed reminders, leadership digest posting
OAuth 2.0 via Slack App
Pro (Workflow Builder features)
Agent 1, Agent 2
Google Sheets
Master OKR data store; response write target; progress calculation source
OAuth 2.0 via Google service account
Google Workspace (any paid tier) or personal Google account
Agent 1, Agent 2
Notion
Cycle summary page creation and archive
OAuth 2.0 via Notion integration token
Notion Plus or above (API access required)
Agent 2
Google Workspace
Calendar scheduling reference; email fallback for non-Slack team leads
OAuth 2.0 via service account
Google Workspace Business Starter or above
Agent 1
Automation platform
Workflow orchestration, schedule trigger, credential store, retry logic
Internal (platform-managed)
Subscription tier supporting webhook listeners and scheduled triggers
Both agents
Before you connect anything: all OAuth flows and API credentials must be tested against sandbox or staging environments before production credentials are entered. Create a test Slack workspace, a duplicate Google Sheet, a sandbox Notion integration, and a non-production Google Workspace account. Only promote to production credentials after each connection passes the checks in the Test and QA Plan. Contact support@gofullspec.com if you need guidance on sandbox setup.
02Per-tool integration detail
Slack
Slack is used by both agents: Agent 1 sends structured update request messages and timed reminders to team leads; Agent 2 posts the formatted leadership digest to a designated channel. A custom Slack App must be created in the workspace and installed with the scopes below. Workflow Builder is not used; the automation platform drives all message delivery directly via the Slack Web API.
Auth method
OAuth 2.0. Create a Slack App at api.slack.com/apps, install to workspace, and store the Bot User OAuth Token (xoxb-...) in the credential store. Token does not expire but must be rotated if revoked.
Required scopes
chat:write | chat:write.public | im:write | users:read | users:read.email | channels:read | groups:read | mpim:read | reactions:read
Webhook / trigger setup
No inbound webhook is required for outbound message delivery. If read receipts or reaction-based confirmation is used, enable Event Subscriptions and subscribe to the message.im and reaction_added event types. Provide the automation platform's inbound URL as the Request URL. Slack sends a URL verification challenge on first save; the platform must respond with the challenge value within 3 seconds.
Required configuration
SLACK_BOT_TOKEN stored in credential store (not hardcoded). SLACK_LEADERSHIP_CHANNEL_ID stored in credential store. SLACK_TEAM_LEAD_USER_IDS stored as a JSON array in the credential store, updated each time the team lead list changes. Reminder intervals (24h, 48h) stored as workflow-level environment variables.
Rate limits
Slack Web API Tier 3: 50 requests/minute for chat.postMessage. At current volume (12 to 30 OKR updates per cycle), peak outbound message burst is under 35 messages. No throttling layer is required, but the orchestration layer must space messages with a minimum 200ms delay between calls to avoid transient 429 responses.
Constraints
Free Slack workspaces restrict Workflow Builder features; however, since the automation platform drives all API calls directly, the Free plan limitation does not affect this build. The Slack App must be installed by a Workspace Owner or Admin. Direct message delivery requires the bot to share a channel with the recipient or have im:write scope; confirm all team leads are reachable via DM before go-live.
// Outbound (Agent 1 -> team lead DM)
POST https://slack.com/api/chat.postMessage
{ channel: <user_id>, text: <structured_update_prompt>, blocks: <Block Kit JSON> }
// Outbound (Agent 2 -> leadership channel)
POST https://slack.com/api/chat.postMessage
{ channel: SLACK_LEADERSHIP_CHANNEL_ID, text: <digest_summary>, blocks: <digest_Block_Kit_JSON> }
// Inbound event (optional reaction confirmation)
POST <platform_inbound_url> <- Slack Event payload
{ type: 'event_callback', event: { type: 'reaction_added', user: <user_id>, reaction: 'white_check_mark' } }Google Sheets
Google Sheets is the master OKR data store. Agent 1 writes submitted key result values to the sheet; Agent 2 reads those values to calculate progress percentages, apply RAG thresholds, and identify at-risk objectives. A dedicated service account is used for all read and write operations. The sheet schema must be finalised before the build starts (defined during the Discovery and OKR Structure Setup stage).
Auth method
OAuth 2.0 via Google service account. Create a service account in Google Cloud Console, generate a JSON key file, and share the target spreadsheet with the service account email address (editor role). Store the service account JSON key in the credential store as GOOGLE_SERVICE_ACCOUNT_JSON.
Required scopes
https://www.googleapis.com/auth/spreadsheets | https://www.googleapis.com/auth/drive.readonly
Webhook / trigger setup
Google Sheets does not natively push events to external endpoints. Agent 2 is triggered by the automation platform polling the sheet (or by an internal flag row written by Agent 1 when the submission window closes). Poll interval: 5 minutes during the active submission window. The SUBMISSION_COMPLETE flag cell (sheet: Control, cell: B2) is set to TRUE by Agent 1 when all responses are received or the window deadline passes.
Required configuration
GOOGLE_SPREADSHEET_ID stored in credential store. Sheet tab names stored as workflow-level variables: SHEET_RESPONSES (default: 'Cycle_Responses'), SHEET_CONTROL (default: 'Control'), SHEET_ARCHIVE_PREFIX (default: 'Archive_'). Column header row must be row 1; data starts row 2. RAG threshold values (GREEN_MIN_PCT, AMBER_MIN_PCT) stored as workflow-level environment variables, not hardcoded in formulas.
Rate limits
Google Sheets API v4: 300 read requests/minute per project; 60 write requests/minute per project. At current volume (12 to 30 rows written per cycle), batch write calls via batchUpdate keep write operations well under limit. No throttling is required. If cycle volume grows beyond 150 rows, implement exponential backoff on write retries.
Constraints
The service account must have editor access to the spreadsheet; viewer access is insufficient for write operations. The sheet must not use merged cells in the data range as these break range reads. Any formula-based columns (e.g. progress percentage auto-calculation) must not overlap with columns the automation writes to; use separate columns for formula outputs.
// Agent 1 write (response submission)
PUT https://sheets.googleapis.com/v4/spreadsheets/{SPREADSHEET_ID}/values/{SHEET_RESPONSES}!A{row}:H{row}
{ values: [[cycle_date, team_lead_id, objective_id, kr_id, current_value, target_value, submitted_at, notes]] }
// Agent 2 read (progress calculation input)
GET https://sheets.googleapis.com/v4/spreadsheets/{SPREADSHEET_ID}/values/{SHEET_RESPONSES}!A:H
-> returns ValueRange { values: [[...row...], ...] }
// Control flag write (Agent 1 signals window close)
PUT https://sheets.googleapis.com/v4/spreadsheets/{SPREADSHEET_ID}/values/Control!B2
{ values: [['TRUE']] }Notion
Notion is used exclusively by Agent 2 to create a new cycle summary page, populate it with the progress table and at-risk flags, and archive it under the designated parent page. A Notion internal integration token is used. The parent page and database IDs must be captured during setup and stored in the credential store.
Auth method
Notion OAuth 2.0 via internal integration. Create an integration at notion.so/my-integrations, copy the Internal Integration Token, and share the target parent page with the integration (editor access). Store the token as NOTION_INTEGRATION_TOKEN in the credential store.
Required scopes
read_content | update_content | insert_content (set during integration creation in the Notion UI; these are capability checkboxes, not OAuth scope strings)
Webhook / trigger setup
Notion does not support outbound webhooks. Agent 2 is triggered by the automation platform (not by Notion). No inbound webhook configuration is required on the Notion side.
Required configuration
NOTION_INTEGRATION_TOKEN in credential store. NOTION_PARENT_PAGE_ID (the OKR archive page) in credential store. NOTION_PAGE_TEMPLATE_PROPERTIES stored as a JSON object defining the expected property names (Cycle Date, Status, At-Risk Count, Link to Sheet) to ensure consistent page structure across cycles. Page titles follow the pattern: OKR Cycle Summary - {cycle_date}.
Rate limits
Notion API: 3 requests/second average; burst up to 10 requests/second. One cycle creates a single page with multiple block writes (typically 10 to 20 API calls). Well within limits. No throttling layer required at current volume.
Constraints
The integration must be explicitly shared with the parent page; workspace-wide access is not granted by default. Rich text block content is limited to 2,000 characters per block; if the digest text exceeds this, it must be split across multiple paragraph blocks. Notion API does not support creation of inline databases via API in all plan tiers; use a page with a table block rather than a full Notion database if the Plus plan is not confirmed.
// Create cycle summary page
POST https://api.notion.com/v1/pages
Authorization: Bearer {NOTION_INTEGRATION_TOKEN}
Notion-Version: 2022-06-28
{ parent: { page_id: NOTION_PARENT_PAGE_ID },
properties: { title: [{ text: { content: 'OKR Cycle Summary - {cycle_date}' } }] },
children: [ <block array: heading, progress table, at-risk list, sheet link> ] }
// Append at-risk block if flagged items > 0
PATCH https://api.notion.com/v1/blocks/{page_id}/children
{ children: [ { type: 'callout', callout: { icon: { emoji: '🔴' }, rich_text: [...] } } ] }Google Workspace (Calendar and Email fallback)
Google Workspace is used by Agent 1 as a scheduling reference to align the cycle trigger with confirmed OKR cadence dates, and as an email fallback channel for any team lead who cannot be reached via Slack DM. Gmail API access is required for the fallback path only; Calendar API is read-only for trigger alignment.
Auth method
OAuth 2.0 via the same Google service account used for Sheets. Grant the service account domain-wide delegation in Google Workspace Admin if calendar read access for multiple users is required. Store as GOOGLE_SERVICE_ACCOUNT_JSON (shared with the Sheets integration).
Required scopes
https://www.googleapis.com/auth/calendar.readonly | https://www.googleapis.com/auth/gmail.send
Webhook / trigger setup
Not applicable. The cycle trigger is schedule-based (set in the automation platform), not calendar-event-driven. The Calendar API is read-only and used only if cycle date validation logic is implemented. The Gmail API send path is invoked only when Slack DM delivery fails for a specific user.
Required configuration
GOOGLE_FALLBACK_EMAIL_FROM stored in credential store (the sending address for email fallback). GOOGLE_CALENDAR_ID (optional, only if calendar-based trigger alignment is enabled) stored in credential store. Email template subject and body stored as workflow-level variables, not hardcoded.
Rate limits
Gmail API: 100 requests/second per user; 25,000 quota units/day. At current volume (maximum 30 fallback emails per cycle), usage is negligible. No throttling required.
Constraints
Domain-wide delegation must be approved by the Google Workspace Admin. If the organisation uses Gmail with personal accounts (not Workspace), domain-wide delegation is unavailable and a user-level OAuth flow is required instead. The email fallback path must only fire after a confirmed Slack DM failure; it must not run in parallel with the Slack path to avoid duplicate notifications.
// Email fallback send (Gmail API)
POST https://gmail.googleapis.com/gmail/v1/users/me/messages/send
Authorization: Bearer {google_access_token}
{ raw: <base64url-encoded RFC 2822 message> }
To: {team_lead_email}
From: {GOOGLE_FALLBACK_EMAIL_FROM}
Subject: 'OKR Update Required - {cycle_date}'
Body: <plain text update request with key result list>Integration and API SpecPage 1 of 3
FS-DOC-05Technical
03Field mappings between tools
The tables below define the exact field mappings for each agent handoff. All field names are shown in monospace format as they appear in the source tool or payload. These mappings must be implemented exactly; any column rename in the Google Sheet requires a corresponding update to the automation platform workflow variables.
Agent 1 handoff: Slack form submission to Google Sheets (OKR Collection Agent writes responses)
Source tool
Source field
Destination tool
Destination field
Slack Block Kit payload
`user.id`
Google Sheets
`team_lead_slack_id` (col A)
Slack Block Kit payload
`user.username`
Google Sheets
`team_lead_name` (col B)
Automation platform (internal)
`cycle_date` (ISO 8601)
Google Sheets
`cycle_date` (col C)
Slack Block Kit payload
`actions[0].block_id` -> objective_id
Google Sheets
`objective_id` (col D)
Slack Block Kit payload
`actions[0].action_id` -> kr_id
Google Sheets
`kr_id` (col E)
Slack Block Kit payload
`actions[0].value`
Google Sheets
`current_value` (col F)
Automation platform (config)
`KR_TARGET_VALUE` env var keyed by kr_id
Google Sheets
`target_value` (col G)
Slack Block Kit payload
`actions[0].action_ts` -> ISO timestamp
Google Sheets
`submitted_at` (col H)
Slack Block Kit payload
`actions[1].value` (optional notes field)
Google Sheets
`notes` (col I)
Automation platform (derived)
Submission status: TRUE/FALSE
Google Sheets
`responded` (col J)
Agent 2 handoff: Google Sheets to Notion (OKR Analysis and Reporting Agent creates cycle summary page)
Source tool
Source field
Destination tool
Destination field
Google Sheets
`cycle_date` (col C)
Notion page
`title` property: 'OKR Cycle Summary - {cycle_date}'
Google Sheets
`objective_id` (col D)
Notion page block
`objective_id` in progress table row
Google Sheets
`kr_id` (col E)
Notion page block
`kr_id` in progress table row
Google Sheets
`current_value` (col F)
Notion page block
`current_value` in progress table row
Google Sheets
`target_value` (col G)
Notion page block
`target_value` in progress table row
Automation platform (derived)
`progress_pct` = (current_value / target_value) * 100
Notion page block
`progress_pct` in progress table row
Automation platform (derived)
`rag_status` (GREEN / AMBER / RED) based on thresholds
Notion page block
`rag_status` in progress table row; also sets Notion page `Status` property
Automation platform (derived)
Count of rows where rag_status = RED
Notion page
`At-Risk Count` property (number)
Google Sheets
`notes` (col I)
Notion page block
`notes` paragraph block per KR row where notes is non-empty
Automation platform (config)
`GOOGLE_SPREADSHEET_URL` env var
Notion page
`Link to Sheet` URL property
Agent 2 handoff: Google Sheets derived data to Slack leadership digest (OKR Analysis and Reporting Agent posts digest)
Source tool
Source field
Destination tool
Destination field
Google Sheets
`cycle_date` (col C)
Slack Block Kit
Header block text: 'OKR Digest - {cycle_date}'
Automation platform (derived)
`total_krs_submitted` count
Slack Block Kit
Section block: '{n} of {total} key results submitted'
Automation platform (derived)
`rag_status` per KR (RED rows)
Slack Block Kit
Section block: ':red_circle: At-risk items list'
Automation platform (derived)
`rag_status` per KR (GREEN rows)
Slack Block Kit
Section block: ':large_green_circle: On-track items list'
Automation platform (derived)
`progress_pct` per KR
Slack Block Kit
Context block: '{kr_id}: {progress_pct}% of target'
Notion (derived)
Newly created Notion page URL
Slack Block Kit
Button block: 'View full summary in Notion' -> URL
04Build stack and orchestration
Orchestration layout
Two discrete workflows in the automation platform, one per agent. Agent 1 (OKR Collection Agent) handles the scheduled trigger, Slack message dispatch, reminder escalation, and Google Sheets write. Agent 2 (OKR Analysis and Reporting Agent) handles progress calculation, RAG status assignment, Notion page creation, and Slack digest posting. The two workflows share a single credential store. Inter-workflow signalling uses the SUBMISSION_COMPLETE flag in the Control sheet tab; Agent 2 polls this flag on a 5-minute interval during the active window.
Agent 1 trigger mechanism
Scheduled time-based trigger. The automation platform cron fires at the configured day and time each week or fortnight (e.g. every Monday 09:00 in the workspace timezone). No webhook or inbound event is used to start Agent 1. The cron schedule is stored as a workflow-level variable (CYCLE_CRON_EXPRESSION) so it can be updated without modifying the workflow logic.
Agent 2 trigger mechanism
Poll-based trigger with a condition check. Agent 2 polls the Google Sheets Control tab (cell B2: SUBMISSION_COMPLETE) every 5 minutes after the Agent 1 cron fires. When the flag is TRUE (set by Agent 1 on full response receipt or window deadline), Agent 2 proceeds. The poll loop has a maximum duration of 72 hours before it times out and raises an alert. No webhook signature validation is required for this internal flag-based trigger.
Slack webhook signature validation
If Slack Event Subscriptions are enabled (for reaction-based confirmation), all inbound Slack event payloads must be verified using the SLACK_SIGNING_SECRET. The automation platform endpoint must compute HMAC-SHA256 over 'v0:{timestamp}:{raw_body}' using the signing secret and compare it to the X-Slack-Signature header value. Reject any request where the computed signature does not match or where the X-Slack-Request-Timestamp is more than 5 minutes old.
Credential store model
All secrets and environment-specific IDs are stored in the automation platform's built-in encrypted credential store. No secret appears in workflow node configuration fields, code blocks, or logs. Credentials are referenced by variable name only.
Workflow environment variables
Non-secret configuration (cron schedule, reminder intervals, sheet tab names, RAG thresholds) is stored as workflow-level environment variables, distinct from the credential store, so they can be updated by the FullSpec team without touching secrets.
Credential store contents (all entries below must be populated before either workflow is activated):
All entries are referenced by variable name in workflow nodes. No value is hardcoded.
// Credential store entries (encrypted at rest, referenced by key name only)
SLACK_BOT_TOKEN // xoxb-... Bot User OAuth Token from Slack App
SLACK_SIGNING_SECRET // From Slack App Basic Information page
SLACK_LEADERSHIP_CHANNEL_ID // Channel ID (not name) for leadership digest
SLACK_TEAM_LEAD_USER_IDS // JSON array: ["U0123ABC", "U0456DEF", ...]
GOOGLE_SERVICE_ACCOUNT_JSON // Full JSON key file for Google service account
GOOGLE_SPREADSHEET_ID // From the master OKR Google Sheet URL
GOOGLE_SPREADSHEET_URL // Full https://docs.google.com/spreadsheets/d/... URL
GOOGLE_FALLBACK_EMAIL_FROM // e.g. okr-automation@[yourdomain].com
GOOGLE_CALENDAR_ID // Optional; only if calendar-based validation is active
NOTION_INTEGRATION_TOKEN // Internal Integration Token from Notion integrations page
NOTION_PARENT_PAGE_ID // UUID of the OKR archive parent page in Notion
// Workflow-level environment variables (non-secret, editable without credential rotation)
CYCLE_CRON_EXPRESSION // e.g. '0 9 * * 1' for every Monday 09:00
SUBMISSION_WINDOW_HOURS // e.g. 48 (hours before window closes)
REMINDER_1_DELAY_HOURS // e.g. 24
REMINDER_2_DELAY_HOURS // e.g. 48
SHEET_RESPONSES // Tab name, default: 'Cycle_Responses'
SHEET_CONTROL // Tab name, default: 'Control'
SHEET_ARCHIVE_PREFIX // Prefix for archived tabs, default: 'Archive_'
GREEN_MIN_PCT // RAG threshold: >= this value = GREEN, e.g. 70
AMBER_MIN_PCT // RAG threshold: >= this value = AMBER, < GREEN, e.g. 40
NOTION_PAGE_TEMPLATE_PROPERTIES // JSON: { 'Cycle Date': 'date', 'Status': 'select', ... }
KR_TARGET_VALUES // JSON map: { 'kr_001': 100, 'kr_002': 50, ... }Integration and API SpecPage 2 of 3
FS-DOC-05Technical
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 automation platform's execution log with a timestamp, the affected node name, the error code or message, and the payload that caused the failure. Where a retry is defined, exponential backoff applies unless stated otherwise.
Integration
Scenario
Required behaviour
Slack / chat.postMessage (Agent 1)
HTTP 429 rate limit on initial message send
Retry up to 3 times with exponential backoff starting at 1 second (1s, 2s, 4s). If all retries fail, log the failure and route the affected team lead to the Gmail email fallback path. Do not skip the team lead silently.
Slack / chat.postMessage (Agent 1)
HTTP 404 or channel_not_found on DM send (user not in workspace or DM blocked)
Do not retry. Log the error with the user ID. Immediately invoke Gmail email fallback. Flag the user ID in the non-responder list for manual review by the ops manager.
Slack / chat.postMessage (Agent 2)
Leadership digest post fails (any 5xx error)
Retry up to 3 times with 5s, 10s, 20s backoff. If all retries fail, send a fallback plain-text notification to the GOOGLE_FALLBACK_EMAIL_FROM address with the digest content as email body. Log the failure and alert the ops manager via a separate Slack DM to the SLACK_OPS_MANAGER_USER_ID credential.
Slack Event Subscriptions (inbound signature validation)
X-Slack-Signature mismatch or timestamp older than 5 minutes
Reject the request immediately with HTTP 403. Do not process the payload. Log the rejection with the source IP and timestamp. Do not retry inbound events; Slack will retry delivery automatically up to 3 times.
Google Sheets / batchUpdate write (Agent 1)
HTTP 429 quota exceeded on response write
Retry up to 5 times with exponential backoff starting at 2 seconds (2s, 4s, 8s, 16s, 32s). If all retries fail, hold the payload in the automation platform's in-memory queue for up to 10 minutes and attempt one final write. If still failing, log the full row payload and alert the ops manager. The cycle must not proceed to Agent 2 until the write is confirmed.
Google Sheets / values.get read (Agent 2)
HTTP 403 permission denied (service account access revoked)
Do not retry. Log the error immediately. Halt Agent 2 execution. Alert the ops manager and the FullSpec support address (support@gofullspec.com) with the error detail. Resume only after credentials are re-verified and re-authorised.
Google Sheets / Control flag poll (Agent 2)
Poll loop reaches 72-hour timeout without SUBMISSION_COMPLETE = TRUE
Stop the poll loop. Log a timeout event. Post an alert Slack DM to SLACK_OPS_MANAGER_USER_ID stating the cycle has not completed within the expected window. Do not auto-proceed to Agent 2 analysis; require manual confirmation or a manual flag set before continuing.
Notion / pages.create (Agent 2)
HTTP 401 or 403 invalid or expired integration token
Do not retry. Log the error. Halt Notion page creation. Post an alert to SLACK_OPS_MANAGER_USER_ID. Send the cycle summary content as a structured Gmail email to the ops manager as a fallback record. Flag for credential rotation before next cycle.
Notion / blocks.children.append (Agent 2)
HTTP 400 validation error (block content exceeds 2,000 character limit)
Catch the error at the block level. Automatically split the oversized block into two sequential paragraph blocks of equal length. Retry the append with the split blocks. Log the split event for audit. Do not halt the page creation for this error.
Notion / pages.create (Agent 2)
HTTP 502 or 503 Notion service unavailable
Retry up to 3 times with 10s, 20s, 40s backoff. If all retries fail, store the full page payload in the automation platform execution log and alert the ops manager. The Slack digest must still be posted using the in-memory derived data even if Notion page creation fails; include a note in the digest that the Notion page is pending.
Google Workspace / Gmail send (fallback path)
HTTP 429 or daily quota exceeded on fallback email
Retry once after 60 seconds. If still failing, log the intended recipient, the cycle date, and the full message body to the execution log. The ops manager must be notified via the primary Slack DM (if available) that email fallback has failed for the named team lead. Manual outreach is required.
Automation platform / scheduled cron trigger (Agent 1)
Cron fires but workflow fails to initialise (platform error or timeout)
The automation platform must capture the missed execution and surface it in the execution history log. If the platform supports missed-run recovery, enable it. If not, configure a secondary health-check ping (e.g. a monitoring endpoint called at cycle start) so that silence on that endpoint triggers an alert to support@gofullspec.com within 30 minutes of the expected fire time.
Unhandled exceptions must never fail silently. If an error scenario is not listed in the table above and the automation encounters an unexpected failure, the default behaviour is: log the full error payload with stack trace, halt the affected workflow branch, and post an alert Slack DM to SLACK_OPS_MANAGER_USER_ID and an email to support@gofullspec.com. Do not swallow errors or allow partial execution states to proceed undetected.
Integration and API SpecPage 3 of 3