Back to Proactive Customer Communication

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

Proactive Customer Communication

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

This document is the definitive integration reference for the Proactive Customer Communication automation. It covers every tool connected in the build, the exact authentication method and scopes required for each, field-level mappings between agent handoffs, the orchestration layout and credential store structure, and the required error handling behaviour at every integration point. The FullSpec team uses this document to configure, verify, and maintain all connections. You and your team do not need to action anything here directly, but your HubSpot property names, Twilio sender IDs, and Intercom workspace details must match what is recorded in Section 04 before build begins.

01Tool inventory

Tool
Role in automation
Auth method
Min plan required
Used by agents
Workflow automation platform
Orchestration layer; hosts all three agent workflows, credential store, and retry logic
Internal service account
Any plan supporting webhooks and API steps
All agents
HubSpot
CRM trigger source, customer data lookup, and activity log write-back
OAuth 2.0 (private app token)
Sales Hub Starter or Service Hub Starter (API access required)
Agent 1, Agent 2, Agent 3
Google Sheets
Customer channel preference lookup table
OAuth 2.0 (service account)
Google Workspace Business Starter or free with service account
Agent 1
Slack
Supervisor approval interface and hourly team digest delivery
OAuth 2.0 (bot token via Slack App)
Free tier sufficient; paid plan required for message retention beyond 90 days
Agent 2, Agent 3
Gmail
Email delivery channel for standard customer messages
OAuth 2.0 (delegated service account or user token)
Google Workspace Business Starter
Agent 3
Intercom
In-app and chat message delivery channel
Bearer token (API key)
Intercom Starter or above
Agent 3
Twilio
SMS delivery channel
HTTP Basic Auth (Account SID + Auth Token)
Pay-as-you-go (Messaging Service SID required)
Agent 3
Before you connect anything: every integration must be validated against a sandbox or staging environment before production credentials are entered. For HubSpot, use a developer test account. For Twilio, use the test credentials and magic numbers. For Intercom, use a sandbox workspace if available, or a test contact in a staging environment. For Gmail and Google Sheets, authenticate against a non-production Google Workspace user first. Slack can be tested in a private channel with no customer exposure. Production credentials must not be stored in workflow steps or environment files; they must live exclusively in the credential store described in Section 04.

02Per-tool integration detail

HubSpot

HubSpot is the trigger source for the entire automation and the destination for all activity log write-backs. A private app token is the recommended auth method for server-to-server integration; OAuth 2.0 user-level tokens are acceptable but require refresh token handling. The automation listens for contact or deal property changes via webhook subscription.

Auth method
OAuth 2.0 private app token (recommended) or OAuth 2.0 authorization code flow with offline access. Token stored in credential store as HUBSPOT_PRIVATE_APP_TOKEN.
Required scopes
crm.objects.contacts.read, crm.objects.contacts.write, crm.objects.deals.read, crm.objects.deals.write, timeline.write, conversations.read, webhooks.webhooks.read, webhooks.webhooks.write, oauth
Webhook / trigger setup
Subscribe to the propertyChange event type on the contact and deal objects. Subscription must target the specific properties that represent notification-eligible statuses (e.g. hs_pipeline_stage, lifecyclestage, or a custom property such as notification_status). Webhook delivery URL is the orchestration platform's inbound endpoint. Signature validation: compute HMAC-SHA256 of the raw request body using the app's client secret and compare to the X-HubSpot-Signature-v3 header. Reject any request where signatures do not match.
Required configuration
Property names for notification-eligible statuses must be agreed and stored in config (HUBSPOT_TRIGGER_PROPERTIES). Pipeline stage IDs for each notification status stored in HUBSPOT_ELIGIBLE_STAGE_IDS. Timeline event type ID for activity log write-back stored in HUBSPOT_TIMELINE_EVENT_TYPE_ID. Portal ID stored in HUBSPOT_PORTAL_ID.
Rate limits
HubSpot private app tokens: 110 requests/10 seconds and 250,000 requests/day on Starter plans. At ~200 touchpoints/month (roughly 7-10 per day), current volume is well below limits. Throttling is not required at current volume, but the orchestration layer must implement a 429 retry with exponential backoff as a safeguard.
Constraints
Webhooks may be delivered more than once (at-least-once delivery). The orchestration layer must deduplicate by storing the last processed objectId and timestamp. Activity log write-backs use the Timeline API; notes written via the Engagements API are an acceptable fallback if timeline event type is not configured.
// Inbound webhook payload (property change)
{ "objectId": "<contact_or_deal_id>", "objectType": "CONTACT" | "DEAL",
  "propertyName": "<trigger_property>", "propertyValue": "<new_value>",
  "changeTimestamp": 1716000000000 }

// Contact lookup response (GET /crm/v3/objects/contacts/{id})
{ "id": "<contact_id>", "properties": {
    "firstname": "Jane", "lastname": "Smith",
    "email": "jane@example.com", "phone": "+1...",
    "preferred_channel": "email" | "sms" | "chat",
    "notification_status": "<trigger_value>" } }

// Activity write-back (POST /crm/v3/timeline/events)
{ "eventTemplateId": "<HUBSPOT_TIMELINE_EVENT_TYPE_ID>",
  "objectId": "<contact_id>",
  "tokens": { "channel": "email", "sent_at": "ISO8601", "message_preview": "..." } }
Google Sheets

Google Sheets holds the fallback and supplementary channel preference lookup table. It is read by Agent 1 (Status Monitor Agent) when the HubSpot contact record does not carry a populated preferred_channel property. Authentication uses a Google service account with the Sheets API enabled; no user-level OAuth flow is needed.

Auth method
OAuth 2.0 service account (JSON key file). Key stored in credential store as GSHEETS_SERVICE_ACCOUNT_JSON. The service account email must be granted Viewer access to the target spreadsheet.
Required scopes
https://www.googleapis.com/auth/spreadsheets.readonly
Webhook / trigger setup
Not applicable. Google Sheets is polled on demand by Agent 1 during the customer preference lookup step. No push notifications or subscriptions are configured.
Required configuration
Spreadsheet ID stored in GSHEETS_PREFERENCE_SHEET_ID. Sheet tab name stored in GSHEETS_PREFERENCE_TAB_NAME (default: 'Preferences'). Column positions for customer identifier (email or HubSpot contact ID), preferred channel, and opt-out flag stored in GSHEETS_COLUMN_MAP.
Rate limits
Google Sheets API: 300 read requests per minute per project, 60 per minute per user. At current volume of ~7-10 lookups per day, no throttling is needed. If volume scales beyond 500 lookups/day, implement a local cache with a 4-hour TTL.
Constraints
The sheet must follow a fixed column structure (contact_id, email, preferred_channel, opt_out). Column order must not change after build. Any structural changes to the sheet require a corresponding config update in GSHEETS_COLUMN_MAP. Rows with an opt_out value of TRUE must cause the orchestration layer to halt processing for that contact.
// Read request (GET spreadsheets/{id}/values/{range})
range: "Preferences!A:D"

// Response row
[ "<hubspot_contact_id>", "jane@example.com", "email" | "sms" | "chat", "FALSE" ]

// Fallback behaviour if contact not found in sheet
preferred_channel defaults to "email"
Slack

Slack serves two distinct functions: the supervisor approval interface used by Agent 2 (Message Drafting Agent) for sensitive drafts, and the hourly team digest channel used by Agent 3 (Delivery and Logging Agent). Both functions use the same Slack App bot token but post to different channels.

Auth method
OAuth 2.0 bot token issued via Slack App installation. Token stored in credential store as SLACK_BOT_TOKEN. App must be installed to the workspace by a Slack admin.
Required scopes
chat:write, chat:write.public, channels:read, im:write, reactions:read, reactions:write, users:read, users:read.email
Webhook / trigger setup
Interactivity must be enabled in the Slack App configuration (App settings > Interactivity and Shortcuts). The Request URL for interactive components must point to the orchestration platform's Slack interaction endpoint. Signature validation: verify the X-Slack-Signature header using HMAC-SHA256 with the Slack signing secret (stored as SLACK_SIGNING_SECRET). Reject any request where timestamp is more than 5 minutes old or signature does not match.
Required configuration
Approval channel ID stored in SLACK_APPROVAL_CHANNEL_ID. Digest channel ID stored in SLACK_DIGEST_CHANNEL_ID. Supervisor user ID or group ID stored in SLACK_SUPERVISOR_USER_ID for @mention in approval messages. Approval timeout in minutes stored in SLACK_APPROVAL_TIMEOUT_MINUTES (recommended: 60).
Rate limits
Slack Web API: Tier 3 methods (chat.postMessage) allow 50+ requests per minute. At current volume, at most 10-15 messages per day are expected. No throttling required. The orchestration layer must respect Retry-After headers on 429 responses.
Constraints
Approval message buttons must carry a unique action_id and a callback_id encoding the HubSpot contact ID and draft ID so the interaction handler can retrieve the correct draft. Approval state must be stored in the orchestration layer (not Slack) to survive platform restarts. If no supervisor approves within SLACK_APPROVAL_TIMEOUT_MINUTES, the message must be escalated, not silently dropped.
// Approval message payload (chat.postMessage)
{ "channel": "<SLACK_APPROVAL_CHANNEL_ID>",
  "blocks": [
    { "type": "section", "text": { "type": "mrkdwn",
        "text": "*Sensitive draft for review*\nContact: Jane Smith\nStatus: Order delayed\nChannel: email" } },
    { "type": "actions", "elements": [
        { "type": "button", "text": { "type": "plain_text", "text": "Approve" },
          "action_id": "approve_draft", "value": "<draft_id>:<contact_id>", "style": "primary" },
        { "type": "button", "text": { "type": "plain_text", "text": "Edit and Approve" },
          "action_id": "edit_draft", "value": "<draft_id>:<contact_id>" } ] } ] }

// Interaction callback payload (from Slack to orchestration endpoint)
{ "type": "block_actions", "actions": [{ "action_id": "approve_draft",
  "value": "<draft_id>:<contact_id>" }],
  "user": { "id": "<supervisor_slack_id>" } }
Integration and API SpecPage 1 of 3
FS-DOC-05Technical
Gmail

Gmail is the primary email delivery channel used by Agent 3 (Delivery and Logging Agent). Messages are sent on behalf of a designated support mailbox using a delegated Google Workspace service account or a user-level OAuth token. Gmail is used when the customer's preferred_channel resolves to 'email' or when no preference is set.

Auth method
OAuth 2.0 delegated service account (preferred) or OAuth 2.0 authorization code with offline access. Token stored in credential store as GMAIL_SERVICE_ACCOUNT_JSON or GMAIL_OAUTH_REFRESH_TOKEN. The impersonated mailbox address stored as GMAIL_SENDER_ADDRESS.
Required scopes
https://www.googleapis.com/auth/gmail.send, https://www.googleapis.com/auth/gmail.readonly (readonly required only if monitoring for replies is in scope)
Webhook / trigger setup
Not applicable for outbound sending. If inbound reply monitoring is added in a future iteration, Gmail Push Notifications via Google Cloud Pub/Sub would be configured at that point.
Required configuration
Sender address stored in GMAIL_SENDER_ADDRESS. Display name stored in GMAIL_SENDER_NAME. Per-status HTML email templates stored in GMAIL_TEMPLATE_IDS (map of status_key to template file path or ID). Reply-to address stored in GMAIL_REPLY_TO if different from sender.
Rate limits
Gmail API: 250 quota units per user per second; sending limit of 2,000 messages per day per Google Workspace account. At ~200 messages/month (fewer than 10 per day), current volume is well within limits. No throttling required.
Constraints
Messages must be constructed as RFC 2822 MIME formatted strings and base64url-encoded before submission to the messages.send endpoint. HTML templates must include a plain-text alternative part. Unsubscribe headers (List-Unsubscribe) must be included for compliance. The sent message ID returned by the API must be stored alongside the HubSpot activity log entry.
// Send request (POST /gmail/v1/users/{userId}/messages/send)
{ "raw": "<base64url-encoded RFC 2822 message>" }

// Decoded message structure
From: Support <support@yourcompany.com>
To: jane@example.com
Subject: Your order update from [YourCompany.com]
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="boundary_string"
List-Unsubscribe: <mailto:unsubscribe@yourcompany.com?subject=unsubscribe>

// API response
{ "id": "<gmail_message_id>", "threadId": "<thread_id>", "labelIds": ["SENT"] }
Intercom

Intercom is the in-app and chat delivery channel used by Agent 3 when the customer's preferred_channel resolves to 'chat'. Messages are sent as outbound conversations using the Intercom REST API. The integration targets an existing Intercom workspace and requires a valid user or contact record in Intercom for each recipient.

Auth method
Bearer token using Intercom Access Token (OAuth app or direct API key). Token stored in credential store as INTERCOM_ACCESS_TOKEN. Workspace ID stored as INTERCOM_WORKSPACE_ID.
Required scopes
For OAuth app: Read users and companies, Write conversations, Read conversations, Read admins. For direct API key: equivalent permissions must be granted in the Intercom settings panel.
Webhook / trigger setup
Not applicable for outbound sending in this build. Intercom webhooks for inbound reply events (conversation.user.replied) may be configured in a future iteration to close the reply monitoring loop currently handled manually.
Required configuration
Admin ID (the Intercom bot or agent that appears as sender) stored in INTERCOM_SENDER_ADMIN_ID. Per-status message body templates stored in config (map of status_key to template string). If the Intercom contact does not exist, the orchestration layer must fall back to email delivery and log the fallback reason.
Rate limits
Intercom REST API: 83 requests per 10 seconds (approximately 500 per minute) on standard plans. At current volume, fewer than 10 messages per day are sent via Intercom. No throttling required. The orchestration layer must handle 429 responses with a 10-second backoff.
Constraints
Outbound messages via the Conversations API create a new conversation thread. If an open conversation already exists for the contact, the platform must check for existing threads (GET /conversations with contact_id filter) before creating a new one to avoid duplicate threads. Contact lookup is by email; the email must match exactly to the Intercom user record.
// Create outbound conversation (POST /conversations)
{ "from": { "type": "admin", "id": "<INTERCOM_SENDER_ADMIN_ID>" },
  "to": { "type": "user", "id": "<intercom_user_id>" },
  "subject": "Update from [YourCompany.com]",
  "body": "<message_body_html>" }

// API response
{ "type": "conversation", "id": "<conversation_id>",
  "created_at": 1716000000, "state": "open" }
Twilio

Twilio is the SMS delivery channel used by Agent 3 when the customer's preferred_channel resolves to 'sms'. Messages are sent via the Twilio Messaging Service to ensure optimal sender selection and compliance. The integration uses Twilio's REST API with HTTP Basic Auth.

Auth method
HTTP Basic Auth using Account SID as username and Auth Token as password. Account SID stored in credential store as TWILIO_ACCOUNT_SID. Auth Token stored as TWILIO_AUTH_TOKEN. These credentials must never appear in workflow step configuration; they must be injected from the credential store at runtime.
Required scopes
Not applicable (Twilio uses account-level credentials, not scoped OAuth tokens). The Account SID used should belong to a sub-account dedicated to this automation to isolate usage and billing.
Webhook / trigger setup
Status callback URL must be configured on the Messaging Service (or per-message via StatusCallback parameter) to receive delivery receipts. The callback URL points to the orchestration platform's Twilio status endpoint. Validate callbacks using Twilio's X-Twilio-Signature header and the TWILIO_AUTH_TOKEN.
Required configuration
Messaging Service SID stored in TWILIO_MESSAGING_SERVICE_SID. This value must be used as the MessagingServiceSid parameter (not a From number) to allow Twilio to select the optimal sender. Status callback URL stored in TWILIO_STATUS_CALLBACK_URL. Opt-out handling: Twilio automatically handles STOP/HELP replies on Messaging Services; confirm this is enabled in the Twilio console.
Rate limits
Twilio Messaging Services: throughput depends on phone number types in the service pool. Long codes: 1 message per second per number. Short codes: 100 messages per second. At fewer than 10 SMS per day at current volume, no throttling is required. The orchestration layer must queue messages and respect a minimum 1-second gap between sends on long code pools.
Constraints
SMS body must not exceed 160 characters for a single segment to avoid carrier splitting and additional cost. Templates must be pre-validated against this limit. Phone numbers in HubSpot must be stored in E.164 format (+1XXXXXXXXXX). The orchestration layer must validate the format before sending and fall back to email if the number is invalid or missing.
// Send SMS (POST /2010-04-01/Accounts/{AccountSid}/Messages.json)
Content-Type: application/x-www-form-urlencoded
MessagingServiceSid=<TWILIO_MESSAGING_SERVICE_SID>
&To=+1XXXXXXXXXX
&Body=Hi Jane, your order has shipped. Track it here: https://...
&StatusCallback=<TWILIO_STATUS_CALLBACK_URL>

// API response
{ "sid": "<message_sid>", "status": "queued",
  "to": "+1XXXXXXXXXX", "from": "<selected_sender>",
  "date_created": "...", "price": null }

// Status callback payload (delivered to orchestration endpoint)
{ "MessageSid": "<message_sid>", "MessageStatus": "delivered" | "failed" | "undelivered",
  "ErrorCode": null | "<code>", "To": "+1XXXXXXXXXX" }

03Field mappings between tools

The tables below define the exact field mappings at each agent handoff boundary. Source and destination field names are given in monospace exactly as they must appear in the orchestration platform's data transformation steps. Any renaming or type coercion required during the handoff is noted in the destination field column.

Agent 1 handoff: Status Monitor Agent to Message Drafting Agent

Source tool
Source field
Destination tool
Destination field
HubSpot
`properties.firstname`
Drafting Agent input
`customer.first_name`
HubSpot
`properties.lastname`
Drafting Agent input
`customer.last_name`
HubSpot
`properties.email`
Drafting Agent input
`customer.email`
HubSpot
`properties.phone`
Drafting Agent input
`customer.phone_e164` (must be validated/formatted)
HubSpot
`properties.preferred_channel`
Drafting Agent input
`customer.channel` (fallback: 'email' if null)
HubSpot
`properties.notification_status`
Drafting Agent input
`event.status_key`
HubSpot
`objectId`
Drafting Agent input
`event.hubspot_contact_id`
HubSpot
`objectType`
Drafting Agent input
`event.object_type`
HubSpot
`changeTimestamp`
Drafting Agent input
`event.triggered_at_ms` (epoch ms)
Google Sheets
`preferred_channel` (row match)
Drafting Agent input
`customer.channel` (overwrites HubSpot value if populated)
Google Sheets
`opt_out`
Drafting Agent input
`customer.opt_out` (boolean; halt if TRUE)

Agent 2 handoff: Message Drafting Agent to Delivery and Logging Agent

Source tool
Source field
Destination tool
Destination field
Drafting Agent output
`customer.first_name`
Gmail / Intercom / Twilio
`recipient.name`
Drafting Agent output
`customer.email`
Gmail / Intercom
`recipient.email`
Drafting Agent output
`customer.phone_e164`
Twilio
`recipient.to_number`
Drafting Agent output
`customer.channel`
Delivery Agent router
`delivery.channel` (routes to correct tool)
Drafting Agent output
`draft.message_body`
Gmail / Intercom / Twilio
`message.body`
Drafting Agent output
`draft.subject_line`
Gmail / Intercom
`message.subject`
Drafting Agent output
`draft.sensitivity_flag`
Delivery Agent router
`routing.requires_approval` (boolean)
Drafting Agent output
`draft.draft_id`
Slack approval block
`action.value` (encoded in button callback)
Drafting Agent output
`event.hubspot_contact_id`
HubSpot Timeline API
`objectId`
Drafting Agent output
`event.status_key`
HubSpot Timeline API
`tokens.status_key`
Slack interaction
`actions[0].value` (decoded draft_id:contact_id)
Delivery Agent
`delivery.approved_draft_id`

Agent 3 handoff: Delivery and Logging Agent to HubSpot activity log and Slack digest

Source tool
Source field
Destination tool
Destination field
Gmail API response
`id`
HubSpot Timeline API
`tokens.send_reference_id`
Intercom API response
`id` (conversation_id)
HubSpot Timeline API
`tokens.send_reference_id`
Twilio status callback
`MessageSid`
HubSpot Timeline API
`tokens.send_reference_id`
Twilio status callback
`MessageStatus`
HubSpot Timeline API
`tokens.delivery_status`
Delivery Agent
`delivery.channel`
HubSpot Timeline API
`tokens.channel`
Delivery Agent
`delivery.sent_at` (ISO8601)
HubSpot Timeline API
`tokens.sent_at`
Delivery Agent
`draft.message_body` (first 200 chars)
HubSpot Timeline API
`tokens.message_preview`
Delivery Agent
`customer.first_name` + `customer.last_name`
Slack digest block
`digest_row.customer_name`
Delivery Agent
`event.status_key`
Slack digest block
`digest_row.status`
Delivery Agent
`delivery.channel`
Slack digest block
`digest_row.channel`
Delivery Agent
`delivery.sent_at`
Slack digest block
`digest_row.sent_at`
Integration and API SpecPage 2 of 3
FS-DOC-05Technical

04Build stack and orchestration

Orchestration layout
Three discrete workflows, one per agent, running on the workflow automation platform. Each workflow is self-contained with its own trigger, steps, and error branch. Shared state (draft status, approval decisions, deduplication log) is managed via a lightweight key-value store or database table within the platform. All credentials are injected from a single shared credential store; no credential values appear in workflow step configuration.
Agent 1 trigger mechanism
Webhook (push). HubSpot sends a propertyChange webhook to the platform's inbound URL the moment a notification-eligible property changes. Signature validation (HMAC-SHA256 using HubSpot client secret) is performed as the first step in the workflow before any processing begins. Duplicate events are suppressed by checking objectId + changeTimestamp against the deduplication log (TTL: 5 minutes).
Agent 2 trigger mechanism
Internal event (push). Agent 1 posts a structured data package to the Agent 2 workflow's internal trigger endpoint upon successful completion. No polling is used. For Slack approval responses, a separate inbound webhook listener receives the Slack interaction callback and resumes the paused Agent 2 workflow using the draft_id as the correlation key. Slack signature validation (HMAC-SHA256 using SLACK_SIGNING_SECRET) is performed on every inbound interaction.
Agent 3 trigger mechanism
Internal event (push). Agent 2 posts the approved message package to the Agent 3 workflow's internal trigger endpoint. Standard (non-sensitive) messages trigger Agent 3 immediately after draft completion. Sensitive messages trigger Agent 3 only after the Slack approval callback is received and validated. Twilio delivery status callbacks are received via a separate inbound webhook endpoint in Agent 3 and update the delivery log accordingly.
Credential store structure
All secrets are stored in the platform's encrypted credential store, referenced by the variable names below. No secret is hardcoded in any workflow step, template, or environment file.
Deduplication store
Key-value table with composite key objectId:changeTimestamp. Entry TTL set to 5 minutes. Implemented using the platform's built-in data store or an equivalent Redis-compatible store.
Approval state store
Persistent table with columns: draft_id (PK), contact_id, draft_body, sensitivity_flag, created_at, approved_by, approved_at, status (pending / approved / timed_out / edited). Retention: 30 days.
All values injected at runtime from the encrypted credential store. Never commit these values to source control or paste them into workflow step fields.
// Credential store: variable names and descriptions

// HubSpot
HUBSPOT_PRIVATE_APP_TOKEN        // Private app token for all HubSpot API calls
HUBSPOT_PORTAL_ID                // HubSpot portal (account) ID
HUBSPOT_TRIGGER_PROPERTIES       // Comma-separated list of property names to watch
HUBSPOT_ELIGIBLE_STAGE_IDS       // JSON map of status_key to pipeline stage ID
HUBSPOT_TIMELINE_EVENT_TYPE_ID   // Timeline event template ID for activity log
HUBSPOT_CLIENT_SECRET            // Used for webhook signature validation

// Google Sheets
GSHEETS_SERVICE_ACCOUNT_JSON     // Full JSON key for service account (base64-encoded)
GSHEETS_PREFERENCE_SHEET_ID      // Spreadsheet ID
GSHEETS_PREFERENCE_TAB_NAME      // Sheet tab name (default: 'Preferences')
GSHEETS_COLUMN_MAP               // JSON map: { contact_id: 0, email: 1, preferred_channel: 2, opt_out: 3 }

// Slack
SLACK_BOT_TOKEN                  // OAuth bot token (xoxb-...)
SLACK_SIGNING_SECRET             // Used for interaction callback signature validation
SLACK_APPROVAL_CHANNEL_ID        // Channel ID for sensitive draft approval messages
SLACK_DIGEST_CHANNEL_ID          // Channel ID for hourly team digest
SLACK_SUPERVISOR_USER_ID         // Slack user ID or group ID for @mention in approvals
SLACK_APPROVAL_TIMEOUT_MINUTES   // Timeout before escalation (recommended: 60)

// Gmail
GMAIL_SERVICE_ACCOUNT_JSON       // Full JSON key for delegated service account (base64-encoded)
GMAIL_SENDER_ADDRESS             // From address (e.g. support@yourcompany.com)
GMAIL_SENDER_NAME                // Display name (e.g. '[YourCompany.com] Support')
GMAIL_REPLY_TO                   // Reply-to address if different from sender
GMAIL_TEMPLATE_IDS               // JSON map of status_key to template file path or ID

// Intercom
INTERCOM_ACCESS_TOKEN            // Bearer token for Intercom REST API
INTERCOM_WORKSPACE_ID            // Intercom workspace ID
INTERCOM_SENDER_ADMIN_ID         // Admin ID that appears as message sender

// Twilio
TWILIO_ACCOUNT_SID               // Twilio Account SID (sub-account preferred)
TWILIO_AUTH_TOKEN                // Twilio Auth Token (used for Basic Auth and callback validation)
TWILIO_MESSAGING_SERVICE_SID     // Messaging Service SID (use instead of From number)
TWILIO_STATUS_CALLBACK_URL       // Orchestration platform endpoint for delivery receipts

05Error handling and retry logic

Unhandled exceptions must never fail silently. Every error path must write a structured log entry (integration name, error code, contact ID, timestamp, retry count) and, where the failure is not resolved after the maximum retry attempts, post an alert to SLACK_APPROVAL_CHANNEL_ID and mark the relevant record in the approval state store as 'error'. No customer communication should be skipped without a logged and alerted record of the failure.
Integration
Scenario
Required behaviour
HubSpot webhook
Signature validation fails on inbound webhook
Reject request immediately with HTTP 403. Log the raw headers and body hash. Do not process the event. Alert to SLACK_APPROVAL_CHANNEL_ID if more than 5 failures occur within 10 minutes (may indicate a configuration change or spoofing attempt).
HubSpot webhook
Duplicate event received (same objectId + changeTimestamp within 5-minute TTL)
Discard silently. Respond with HTTP 200 to prevent HubSpot retry loop. Increment deduplication counter in logs; do not alert unless count exceeds 50 per hour.
HubSpot API
Contact or deal lookup returns 404 (record deleted or ID mismatch)
Halt processing for this event. Log the objectId, the trigger timestamp, and the 404 response. Post alert to SLACK_APPROVAL_CHANNEL_ID with contact ID so a team member can investigate. Do not retry.
HubSpot API
API returns 429 (rate limit exceeded)
Pause and retry after the number of seconds specified in the Retry-After response header. Maximum 5 retries with exponential backoff (base 2 seconds). If all retries fail, post alert and log failure with status 'rate_limit_exhausted'.
HubSpot API
Timeline event write-back returns 5xx error
Retry up to 3 times with 5-second exponential backoff. If all retries fail, log the failed write payload to the approval state store for manual replay. Post alert to SLACK_APPROVAL_CHANNEL_ID. The message has already been sent; the logging failure must not cause a re-send.
Google Sheets
Contact not found in preference sheet
Default preferred_channel to 'email'. Log the lookup miss with the contact ID. Do not halt processing.
Google Sheets
Sheet API returns 403 (service account permissions revoked)
Halt Agent 1 for all subsequent events. Post immediate alert to SLACK_APPROVAL_CHANNEL_ID and log the error. Fall back to HubSpot preferred_channel property only until credentials are restored.
Slack
Approval message delivery fails (Slack API 5xx)
Retry up to 3 times with 10-second backoff. If all retries fail, escalate via email to GMAIL_SENDER_ADDRESS with the draft content and contact details so a supervisor can act manually. Log failure with draft_id and set approval state to 'slack_delivery_failed'.
Slack
No supervisor approves within SLACK_APPROVAL_TIMEOUT_MINUTES
Set approval state to 'timed_out'. Post a follow-up message in SLACK_APPROVAL_CHANNEL_ID tagging SLACK_SUPERVISOR_USER_ID. Hold the draft; do not send the message automatically. Log the timeout with contact ID and draft ID. A second timeout (after a further SLACK_APPROVAL_TIMEOUT_MINUTES) triggers an email alert to GMAIL_SENDER_ADDRESS.
Gmail
Send API returns 4xx (invalid recipient address or quota exceeded)
Do not retry on 4xx (permanent failure). Log the error code, recipient address, and draft ID. Post alert to SLACK_APPROVAL_CHANNEL_ID. If the failure is quota-related (403 with rateLimitExceeded), queue the message and retry after 60 seconds up to 3 times before alerting.
Intercom
Contact not found in Intercom workspace (404 on user lookup)
Fall back to Gmail delivery using customer.email. Log the fallback with the contact ID and reason. Update the delivery log to reflect the actual channel used. Do not alert unless fallback also fails.
Twilio
Message delivery status callback returns 'failed' or 'undelivered'
Log the MessageSid, ErrorCode, and recipient number. Update the HubSpot activity log token delivery_status to 'failed'. Post alert to SLACK_APPROVAL_CHANNEL_ID. Do not automatically retry SMS delivery; a team member must review the ErrorCode and decide whether to resend via an alternative channel.
Twilio
Phone number fails E.164 validation before send attempt
Halt SMS delivery for this contact. Fall back to Gmail if customer.email is present. Log the invalid number and contact ID. Post alert to SLACK_APPROVAL_CHANNEL_ID noting the data quality issue so the HubSpot record can be corrected.
All retry logic must use jitter (random additional delay of 0-20% of the backoff interval) to prevent thundering herd behaviour if multiple events fail simultaneously. Retry counters and backoff state must be persisted in the approval state store, not held in memory, so that platform restarts do not reset retry counts. Contact support@gofullspec.com if any integration consistently exceeds two retries per day, as this indicates an upstream configuration issue that requires investigation.
Integration and API SpecPage 3 of 3

More documents for this process

Every document generated for Proactive Customer Communication.

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