Back to Competitor Intelligence Tracking

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

Competitor Intelligence Tracking

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

This document defines every integration point, authentication method, required scope, field mapping, and error-handling behaviour for the Competitor Intelligence Tracking automation. It is written for the FullSpec build team and covers five production tools plus the orchestration layer. All credential setup, scope configuration, and webhook registration described here is handled by FullSpec. The owner team is responsible for provisioning API access on each platform and supplying credentials to the FullSpec credential store before build begins.

01Tool inventory

Tool
Role in automation
Auth method
Min plan required
Used by agent
Orchestration layer
Scheduling, workflow execution, credential brokering
Internal service account
Paid tier (any)
Both agents
Google Sheets
Competitor list and source config; read on every daily scan
OAuth 2.0 (Google account)
Free (Google Workspace or personal)
Intelligence Agent (A1)
Notion
Structured intelligence database; signals written daily, read Friday
OAuth 2.0 (Notion integration token)
Free (or Plus for advanced permissions)
Intelligence Agent (A1), Digest Agent (A2)
HubSpot
CRM deal note updates when a matched competitor signal is logged
OAuth 2.0 (private app token)
Starter CRM or above (API access required)
Intelligence Agent (A1)
Slack
Weekly digest delivery to the sales channel every Friday 8 AM
Bot token (OAuth 2.0 app install)
Free or Pro
Digest Agent (A2)
Gmail
Optional digest email to sales manager after Slack post
OAuth 2.0 (Google account, send scope)
Free (Google Workspace or personal)
Digest Agent (A2)
Before you connect anything: provision and validate every credential in a sandbox or test environment before touching production. For Google Sheets and Gmail, use a dedicated service account distinct from any personal login. For HubSpot, create a private app scoped only to the permissions listed in Section 02. For Notion, install the integration against a duplicate test database first. For Slack, install the bot to a private test channel before granting access to the live sales channel. Never hardcode credentials in workflow nodes.

02Per-tool integration detail

Google Sheets

Read-only data source providing the competitor list and monitored source URLs. Polled by the orchestration layer on every daily scan trigger at 6 AM.

Auth method
OAuth 2.0 via Google service account. JSON key file stored in credential store as GSHEETS_SERVICE_ACCOUNT_KEY. Domain-wide delegation is not required; share the target spreadsheet directly with the service account email.
Required scopes
https://www.googleapis.com/auth/spreadsheets.readonly
Trigger / webhook
No webhook. The orchestration layer polls the sheet on a scheduled basis each morning at 06:00 local time using the Sheets API v4 GET spreadsheets/{spreadsheetId}/values/{range} endpoint.
Required configuration
Spreadsheet ID stored in credential store as GSHEETS_COMPETITOR_SHEET_ID (never hardcoded). Named range 'CompetitorSources' must exist in the sheet covering columns: competitor_name, website_url, news_keywords, alert_feed_url, active (boolean). The sheet must be shared with the service account email address before first run.
Rate limits
Google Sheets API v4: 300 read requests per minute per project, 60 requests per minute per user. At current volume (one read per daily scan, approximately 30 reads per month), throttling is not required. If the competitor list grows beyond 50 rows, batch the range read into a single call to remain well within limits.
Constraints
The named range 'CompetitorSources' must not contain merged cells. The 'active' column must be a plain TRUE/FALSE value for the filter logic to parse correctly. Any row with active=FALSE is skipped by the scan. Column order must not be changed post-build without updating the field mapping in the orchestration layer.
// Input
spreadsheetId: GSHEETS_COMPETITOR_SHEET_ID  (from credential store)
range: 'CompetitorSources'
// Output
competitor_name: string
website_url: string
news_keywords: string
alert_feed_url: string
active: boolean
Notion

Primary intelligence database. The Intelligence Agent writes one record per qualifying signal. The Digest Agent reads the current week's records each Friday morning to compile the briefing.

Auth method
Notion internal integration token (OAuth 2.0). Token stored in credential store as NOTION_INTEGRATION_TOKEN. The integration must be added as a connection to both the intelligence database page and any parent workspace page that wraps it.
Required scopes
Read content: read_content. Insert/update records: update_content. No user or comment scopes required.
Trigger / webhook
No inbound webhook from Notion. Digest Agent reads via a scheduled trigger on the orchestration layer (Friday 07:45 AM, 15 minutes before the Slack post deadline). Database query uses POST /v1/databases/{database_id}/query with a filter on the 'Signal Date' property (date on or after the preceding Friday) to retrieve the current week's entries only.
Required configuration
NOTION_DATABASE_ID stored in credential store. Database schema must include the following properties exactly: 'Competitor' (select), 'Category' (select: Pricing, Product, Market Expansion, Messaging, Leadership, Review Signal), 'Relevance Score' (number, 1-5), 'Source URL' (url), 'Signal Date' (date), 'Summary' (rich text), 'HubSpot Deal ID' (rich text, optional). Property names are case-sensitive in Notion API calls.
Rate limits
Notion API: 3 requests per second average; bursts up to approximately 90 requests per minute tolerated. At current volume (~60 writes per month, ~4 per day, plus one bulk read per week), throttling is not required. If signal volume increases significantly, introduce a 350 ms delay between consecutive page creation calls.
Constraints
The Notion integration must have explicit page access granted; workspace-level access is not assumed. Notion rich text fields have a 2,000 character limit per block; AI-generated summaries must be truncated to 1,800 characters before write to leave margin. Select property options ('Category' and 'Competitor') must be pre-populated in the database or the API will reject the value unless the integration has insert_content permission to create new options.
// Input (write - Intelligence Agent)
database_id: NOTION_DATABASE_ID
Competitor: string  (must match existing select option)
Category: string  (Pricing | Product | Market Expansion | Messaging | Leadership | Review Signal)
Relevance Score: integer  (3-5, threshold-filtered)
Source URL: string
Signal Date: ISO8601 date
Summary: string  (max 1800 chars)
HubSpot Deal ID: string | null
// Output (read - Digest Agent)
Array of page objects filtered by Signal Date >= last Friday
HubSpot

CRM integration. When a logged signal matches a competitor tracked against one or more open deals, the orchestration layer appends a timestamped note to each matched deal record.

Auth method
HubSpot private app token (Bearer token). Stored in credential store as HUBSPOT_PRIVATE_APP_TOKEN. Private apps are preferred over legacy API keys. Create the private app under Settings > Integrations > Private Apps with only the scopes listed below.
Required scopes
crm.objects.deals.read, crm.objects.deals.write, crm.objects.notes.write, crm.objects.contacts.read
Trigger / webhook
No inbound webhook. The orchestration layer queries HubSpot after each qualifying Notion write. Endpoint: GET /crm/v3/objects/deals?filters to find open deals where the 'Competitor' property contains the matched competitor name. Matching uses case-insensitive string comparison against the competitor_name value from Google Sheets.
Required configuration
HUBSPOT_PORTAL_ID stored in credential store. A custom deal property named 'competitor_tracked' (type: enumeration, multi-select) must be set up in HubSpot before go-live. Competitor name values in this property must match exactly the competitor_name strings in the Google Sheets CompetitorSources range. A mapping reference document aligning these values is required as a pre-build deliverable from the owner team (see Implementation Notes in the Handover Pack).
Rate limits
HubSpot API (Starter): 110 requests per 10 seconds, 250,000 requests per day. At current volume (~60 signals per month, maximum 60 deal note writes per month), throttling is not required. The orchestration layer must implement a 100 ms delay between consecutive deal note creation calls during a batch to stay within burst limits.
Constraints
Deal note creation uses POST /crm/v3/objects/notes with an association to the deal object. Notes are append-only; the automation never modifies or deletes existing notes. If a competitor matches zero open deals, the step is skipped silently and logged to the orchestration run log. HubSpot Starter does not support custom association labels; notes are associated via the standard DEAL association type only.
// Input (deal lookup)
filter: { propertyName: 'competitor_tracked', operator: 'CONTAINS_TOKEN', value: competitor_name }
filter: { propertyName: 'dealstage', operator: 'NOT_IN', value: ['closedwon','closedlost'] }
// Input (note creation)
properties.hs_note_body: '[COMPETITOR INTEL - {Signal Date}] {Category}: {Summary} | Source: {Source URL}'
associations: [{ to: { id: deal_id }, types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 214 }] }]
// Output
note_id: string
associated_deal_id: string
Slack

Digest delivery channel. The Digest Agent posts the formatted weekly competitive briefing to the designated sales Slack channel each Friday at 8 AM.

Auth method
Slack bot token (xoxb- prefixed OAuth 2.0 token). Stored in credential store as SLACK_BOT_TOKEN. Install the Slack app to the workspace via the OAuth flow; the bot must be added to the target channel before first run.
Required scopes
chat:write, chat:write.public (if the channel is public), channels:read
Trigger / webhook
No inbound webhook from Slack. The orchestration layer posts outbound via chat.postMessage at the conclusion of the Digest Agent run on Friday 08:00. SLACK_SALES_CHANNEL_ID stored in credential store (use channel ID, not channel name, to prevent breakage if the channel is renamed).
Required configuration
SLACK_SALES_CHANNEL_ID stored in credential store. Message is formatted using Slack Block Kit with a Header block ('Weekly Competitor Intelligence Brief - {date}'), one Section block per competitor group (competitor name as bold text, bullet list of signal summaries), and a Context block with a link to the Notion database view. Maximum 50 blocks per message; if signal groups exceed this, split into a thread reply.
Rate limits
Slack API: 1 request per second for chat.postMessage (Tier 3). At current volume (one post per week, occasional thread replies), throttling is not required. If the digest is split into thread replies, insert a 1.1 second delay between each reply call.
Constraints
The bot must be a member of the channel. If the channel is private, chat:write.public is not sufficient; the bot must be explicitly invited. Slack message text fields have a 3,000 character limit per block; the Digest Agent must chunk output accordingly. Unfurling of Notion links can be disabled per post using unfurl_links: false to keep the message clean.
// Input
channel: SLACK_SALES_CHANNEL_ID
blocks: Block Kit JSON array
  - Header: 'Weekly Competitor Intel Brief - {YYYY-MM-DD}'
  - Section per competitor: bold name + signal bullet list
  - Context: Notion database URL
unfurl_links: false
// Output
ts: string  (message timestamp, stored for thread reply chaining if needed)
Gmail

Optional digest email to the sales manager sent after the Slack post. Uses the same compiled digest content as the Slack message, formatted as HTML email.

Auth method
OAuth 2.0 via Google service account with domain-wide delegation, or a dedicated Gmail account authorised via OAuth consent flow. Token stored in credential store as GMAIL_OAUTH_TOKEN. The sending account must be confirmed with the owner before build.
Required scopes
https://www.googleapis.com/auth/gmail.send
Trigger / webhook
No inbound webhook. Triggered sequentially after the Slack post completes on Friday 08:00. Uses Gmail API v1 POST /gmail/v1/users/me/messages/send with a base64url-encoded RFC 2822 message payload.
Required configuration
GMAIL_SENDER_ADDRESS stored in credential store. GMAIL_MANAGER_RECIPIENT stored in credential store (sales manager email address). Email subject template: 'Competitor Intel Brief - Week of {Monday date}'. HTML body mirrors Slack digest with competitor group headings and a hyperlinked button to the Notion database. The feature flag GMAIL_DIGEST_ENABLED (boolean, stored in credential store) controls whether this step fires; set to false to skip without modifying the workflow.
Rate limits
Gmail API: 250 quota units per user per second; send message costs 100 units. Daily sending limit: 10,000 messages per day (Workspace) or 500 per day (personal). At current volume (one email per week), throttling is never required.
Constraints
The OAuth consent screen must be published (not in test mode) if using a personal Google account, or the token will expire after 7 days. For Google Workspace accounts, the service account must be granted the gmail.send scope via the Admin console. Attachments are not used in this integration. Email is not sent if the Slack post step fails, to avoid duplicate partial notifications.
// Input
to: GMAIL_MANAGER_RECIPIENT
from: GMAIL_SENDER_ADDRESS
subject: 'Competitor Intel Brief - Week of {Monday YYYY-MM-DD}'
body: HTML string (competitor groups, signal summaries, Notion link)
condition: GMAIL_DIGEST_ENABLED == true AND Slack post succeeded
// Output
message_id: string  (Gmail message ID for logging)
Integration and API SpecPage 1 of 3
FS-DOC-05Technical

03Field mappings between tools

The following tables define every field handoff between tools across both agent execution paths. Use exact field names as shown; these are the strings the orchestration layer references in its mapping configuration. Monospace names reflect the actual property keys used in API payloads.

Handoff 1: Google Sheets to Intelligence Agent (daily scan input)

Source tool
Source field
Destination tool
Destination field
Google Sheets
`competitor_name`
Intelligence Agent context
`competitor_name`
Google Sheets
`website_url`
Intelligence Agent context
`source_url`
Google Sheets
`news_keywords`
Intelligence Agent context
`search_keywords`
Google Sheets
`alert_feed_url`
Intelligence Agent context
`rss_feed_url`
Google Sheets
`active`
Orchestration filter
`skip_if_false`

Handoff 2: Intelligence Agent scored output to Notion database (write on qualifying signals)

Source tool
Source field
Destination tool
Destination field
Intelligence Agent
`competitor_name`
Notion
`Competitor` (select)
Intelligence Agent
`signal_category`
Notion
`Category` (select)
Intelligence Agent
`relevance_score`
Notion
`Relevance Score` (number)
Intelligence Agent
`source_url`
Notion
`Source URL` (url)
Intelligence Agent
`signal_date`
Notion
`Signal Date` (date, ISO8601)
Intelligence Agent
`summary_text`
Notion
`Summary` (rich text, max 1800 chars)
Intelligence Agent
`matched_deal_id`
Notion
`HubSpot Deal ID` (rich text, nullable)

Handoff 3: Intelligence Agent to HubSpot (deal note creation on competitor match)

Source tool
Source field
Destination tool
Destination field
Intelligence Agent
`competitor_name`
HubSpot deal filter
`competitor_tracked` (contains token)
Intelligence Agent
`signal_date`
HubSpot note body
`hs_note_body` (date prefix)
Intelligence Agent
`signal_category`
HubSpot note body
`hs_note_body` (category label)
Intelligence Agent
`summary_text`
HubSpot note body
`hs_note_body` (body text)
Intelligence Agent
`source_url`
HubSpot note body
`hs_note_body` (appended source link)
HubSpot
`id` (deal object)
Notion
`HubSpot Deal ID` (rich text, written back)

Handoff 4: Notion to Digest Agent (weekly Friday read)

Source tool
Source field
Destination tool
Destination field
Notion
`Competitor` (select value)
Digest Agent grouping
`group_key`
Notion
`Category` (select value)
Digest Agent
`signal_type`
Notion
`Relevance Score` (number)
Digest Agent sort
`sort_score` (descending)
Notion
`Signal Date` (date)
Digest Agent
`entry_date`
Notion
`Summary` (rich text)
Digest Agent
`signal_summary`
Notion
`Source URL` (url)
Digest Agent
`source_link`

Handoff 5: Digest Agent to Slack (weekly post)

Source tool
Source field
Destination tool
Destination field
Digest Agent
`group_key`
Slack Block Kit
`section.text` (bold competitor heading)
Digest Agent
`signal_summary` (array per group)
Slack Block Kit
`section.text` (bullet list)
Digest Agent
`signal_type`
Slack Block Kit
`section.text` (label prefix per bullet)
Digest Agent
`entry_date`
Slack Block Kit
`context.text` (date range label)
Notion database URL
`NOTION_DATABASE_URL`
Slack Block Kit
`context.elements[].url`

Handoff 6: Digest Agent to Gmail (optional email)

Source tool
Source field
Destination tool
Destination field
Digest Agent
`group_key`
Gmail HTML body
`<h2>` competitor section heading
Digest Agent
`signal_summary` (array per group)
Gmail HTML body
`<ul><li>` bullet list
Digest Agent
`signal_type`
Gmail HTML body
`<strong>` label prefix per item
Digest Agent
`week_start_date`
Gmail subject
`Week of {YYYY-MM-DD}` in subject line
Notion database URL
`NOTION_DATABASE_URL`
Gmail HTML body
`<a href>` CTA button

04Build stack and orchestration

Orchestration layout
Two discrete workflows, one per agent: 'Intelligence Agent Workflow' (daily) and 'Digest Agent Workflow' (weekly Friday). Both share a single credential store. No cross-workflow API calls; the Notion database is the only shared state between them. Each workflow is independently deployable and testable.
Intelligence Agent trigger
Scheduled poll: fires daily at 06:00 AM (owner's local timezone, configurable). No inbound webhook. The trigger reads the Google Sheets CompetitorSources range as its first step. If the sheet is unreachable, the workflow aborts and logs an error to the orchestration run log; it does not retry the sheet read (see Section 05).
Digest Agent trigger
Scheduled poll: fires every Friday at 07:45 AM (15 minutes pre-post buffer for Notion query and AI compilation). No inbound webhook. The trigger has no dependency on the Intelligence Agent Workflow completing that morning; it reads from Notion directly. A secondary time-based safety check confirms the current day is Friday before executing; if not Friday, the workflow exits cleanly.
Credential store structure
All secrets stored in the orchestration platform's built-in encrypted credential store. No credentials appear in workflow node configurations, environment variable files, or version-controlled code. See code block below for the full credential manifest.
Webhook signature validation
No inbound webhooks are used in this automation. All triggers are outbound scheduled polls. Slack sends no inbound events; HubSpot webhooks are not used. If future webhook triggers are added, HMAC-SHA256 signature validation must be implemented before processing any payload.
AI model invocation
Both agents invoke an AI language model via the orchestration platform's built-in AI node or a direct API call to the configured LLM provider. The model provider credential is stored as AI_API_KEY. Prompts are stored as static text within the workflow nodes, not fetched externally. The relevance scoring prompt instructs the model to return a JSON object with relevance_score (integer 1-5), signal_category (string), and summary_text (string) only.
Relevance threshold
Signals with relevance_score less than 3 are discarded and not written to Notion or HubSpot. The threshold value is stored as RELEVANCE_THRESHOLD (integer) in the credential store so it can be adjusted without modifying the workflow.
Credential store manifest: full list of secrets required across both workflows
// Credential store manifest
// All entries are encrypted at rest in the orchestration platform.
// Never expose these values in workflow node UI, logs, or version control.

GSHEETS_SERVICE_ACCOUNT_KEY      // JSON key file (base64-encoded) for Google Sheets read access
GSHEETS_COMPETITOR_SHEET_ID      // Google Sheets spreadsheet ID (string)

NOTION_INTEGRATION_TOKEN         // Notion internal integration secret (secret_xxx...)
NOTION_DATABASE_ID               // Notion database ID (32-char hex string)
NOTION_DATABASE_URL              // Full public URL to Notion database view (for digest links)

HUBSPOT_PRIVATE_APP_TOKEN        // HubSpot private app Bearer token (pat-xxx...)
HUBSPOT_PORTAL_ID                // HubSpot portal/account ID (integer)

SLACK_BOT_TOKEN                  // Slack bot OAuth token (xoxb-xxx...)
SLACK_SALES_CHANNEL_ID           // Slack channel ID (C0XXXXXXXXX, not channel name)

GMAIL_OAUTH_TOKEN                // Gmail OAuth 2.0 refresh token for sending account
GMAIL_SENDER_ADDRESS             // Sending email address (string)
GMAIL_MANAGER_RECIPIENT          // Sales manager email address (string)
GMAIL_DIGEST_ENABLED             // Feature flag boolean: true | false

AI_API_KEY                       // API key for the AI language model provider
RELEVANCE_THRESHOLD              // Integer (default: 3); signals below this score are discarded

// Rotation policy: rotate all tokens every 90 days or immediately on suspected compromise.
// HubSpot private app tokens do not expire but must be rotated manually on staff offboarding.
Integration and API SpecPage 2 of 3
FS-DOC-05Technical

05Error handling and retry logic

Unhandled exceptions must never fail silently. Every integration point must produce a structured error log entry in the orchestration run log, including the integration name, error code or HTTP status, timestamp, and the input payload that caused the failure (with any credential values redacted). If a failure affects data completeness (a signal not logged, a deal note not written), an alert must be sent to the FullSpec monitoring channel or the owner-configured fallback address.
Integration
Scenario
Required behaviour
Google Sheets (read)
Sheet unreachable or spreadsheet ID invalid (4xx/5xx)
Abort daily scan immediately. Log error with HTTP status and sheet ID. Do not attempt partial runs. Send alert to owner fallback email. No retry on the same execution; the next scheduled run (following day) retries automatically.
Google Sheets (read)
Named range 'CompetitorSources' not found
Abort and log a schema validation error with the expected range name. Alert owner. No retry until the sheet structure is corrected. Do not proceed with an empty competitor list.
AI model invocation
Model API returns 429 (rate limit) or 503 (service unavailable)
Retry with exponential backoff: 5 s, 15 s, 45 s (3 attempts). If all retries fail, log the raw signal text and mark it as 'pending_review' in the orchestration run log for manual triage. Do not discard the signal silently.
AI model invocation
Model returns malformed JSON or missing required fields (relevance_score, signal_category, summary_text)
Log the raw model output and the competitor/source that triggered it. Skip the signal for this run and mark it 'parse_error' in the run log. Do not write a partial record to Notion. Alert FullSpec monitoring if parse errors exceed 3 in a single run.
Notion (write)
POST to database returns 400 (invalid property value, e.g. unrecognised select option)
Catch the 400 response body and log the offending property name and value. Retry once after correcting the select option if it is a known enum value; otherwise queue the signal for manual Notion entry and alert owner. Do not silently drop the signal.
Notion (write)
POST returns 429 (rate limit)
Retry with a 2 s delay between each attempt, up to 5 retries. If all retries fail, write the signal payload to the orchestration run log as a structured fallback record so it can be manually inserted. Alert owner if more than 2 signals are dropped in one run.
HubSpot (deal lookup)
GET deals returns 401 (invalid or expired token)
Abort the HubSpot step for all signals in the current run. Log the error and alert owner to rotate the HUBSPOT_PRIVATE_APP_TOKEN. Notion writes are not blocked; the HubSpot step is skipped cleanly. The matched_deal_id field in Notion is left null for affected records.
HubSpot (note creation)
POST note returns 404 (deal ID no longer exists)
Log the missing deal ID and skip note creation for that deal. Do not retry. Update the Notion record's HubSpot Deal ID field to 'DEAL_NOT_FOUND' so the mismatch is visible during manual review.
HubSpot (deal lookup)
Competitor name in Google Sheets does not match any competitor_tracked value in HubSpot deals
Skip HubSpot note creation silently for that competitor. Log a 'no_deal_match' entry in the run log with the competitor name. Accumulate these across the run and include a summary in the weekly run report so the owner can align naming conventions.
Notion (read, Digest Agent)
Database query returns zero results for the current week
Post a brief Slack message to the sales channel: 'No new competitor signals were logged this week. Review the competitor source list if this is unexpected.' Do not post a blank digest. Log the empty result with the query date range.
Slack (post)
chat.postMessage returns 404 (channel not found) or 403 (bot not in channel)
Retry once after 10 s. If retry fails, fall back to sending the digest via Gmail regardless of the GMAIL_DIGEST_ENABLED flag. Log the Slack error with channel ID and alert FullSpec monitoring. Do not fail the entire Digest Agent run silently.
Gmail (send)
Send returns 401 (token expired or revoked)
Log the auth failure and alert owner to re-authorise the Gmail OAuth token. Skip the email step for this run; the Slack post is not rolled back. If Gmail is the fallback for a failed Slack post, escalate the alert to both the owner and the FullSpec support inbox at support@gofullspec.com.
All error alerts sent to the owner should include: the workflow name, the step that failed, the UTC timestamp, the error code or message, and a link to the full orchestration run log. Never include raw credential values or full API response bodies containing sensitive data in alert messages. Contact the FullSpec team at support@gofullspec.com if a recurring error pattern cannot be resolved through the run log.
Integration and API SpecPage 3 of 3

More documents for this process

Every document generated for Competitor Intelligence Tracking.

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