FS-DOC-05Technical
Integration and API Spec
FAQ & First Response Automation
[YourCompany.com] · Customer Support Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for every API connection, authentication requirement, field mapping, and error handling rule in the FAQ and First Response Automation build. It is written for the FullSpec engineering team and covers Zendesk, Notion, HubSpot, Slack, and Gmail across three agents: the Ticket Classification Agent, the First Response Drafting Agent, and the Escalation and Logging Agent. All credential management, throttle decisions, and failure behaviours described here must be implemented exactly as specified before any production traffic is routed through the automation.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by agents
Zendesk
Ticket inbox trigger, tag/priority write, reply send, low-confidence queue routing
OAuth 2.0 (subdomain-scoped)
Suite Team ($55/mo)
Agent 1, Agent 2
Notion
Knowledge base query for FAQ article content
Notion Integration Token (internal)
Plus ($16/mo)
Agent 1, Agent 2
HubSpot
Customer contact lookup and activity note creation
OAuth 2.0 (private app token)
Starter CRM ($45/mo)
Agent 3
Slack
Escalation alert post to designated support channel
OAuth 2.0 (Bot Token, scopes-based)
Free tier sufficient
Agent 3
Gmail
Fallback email send channel when Zendesk reply API fails
OAuth 2.0 (Google Workspace, service account optional)
Google Workspace Business Starter
Agent 2
Orchestration layer
Workflow automation platform hosting all agent workflows, credential store, and retry logic
Internal (platform-managed)
Platform subscription (FullSpec-selected)
All agents
Before you connect anything: every tool connection must be validated against a sandbox or staging environment before production credentials are entered. For Zendesk, use a sandbox subdomain. For HubSpot, use a developer test account. For Notion, use a duplicate integration on a test workspace. For Slack, use a private test channel. Only after a clean end-to-end smoke test in sandbox should production credentials be loaded into the credential store.
Integration and API SpecPage 1 of 4
FS-DOC-05Technical
02Per-tool integration detail
Zendesk
Primary ticket source and reply destination. Triggers the entire workflow via webhook on new ticket creation. Also receives tag writes, priority assignments, routing actions, and outbound reply sends from Agents 1 and 2.
Auth method
OAuth 2.0. Register an OAuth client inside Zendesk Admin > Apps and Integrations > OAuth Clients. Store client_id, client_secret, and refresh_token in the credential store. Token endpoint: https://{subdomain}.zendesk.com/oauth/tokens
Required scopes
tickets:read tickets:write users:read users:write
Webhook / trigger setup
Create a Zendesk Trigger under Business Rules > Triggers. Condition: ticket is created AND channel is any. Action: notify active webhook. Payload must include ticket.id, ticket.subject, ticket.description, ticket.requester.email, ticket.created_at. Enable HMAC-SHA256 signature validation using the shared secret stored in the credential store as ZENDESK_WEBHOOK_SECRET. The orchestration layer must verify the X-Zendesk-Webhook-Signature header on every inbound payload before processing.
Required configuration
Zendesk subdomain stored as ZENDESK_SUBDOMAIN. Tag taxonomy agreed and locked before build (e.g. faq, billing, technical, escalation, low-confidence). Priority values must match Zendesk's native enum: low, normal, high, urgent. Routing queue IDs (group IDs) stored in credential store, not hardcoded.
Rate limits
Zendesk REST API: 700 requests/minute on Suite Team. At 220 tickets/month (approx. 0.3 tickets/minute average, up to ~10/minute peak), no throttling is required. Build should include a 429-aware retry handler as a precaution.
Constraints
Webhook payload size limit: 256 KB. Attachments are not forwarded; only text body is processed. Zendesk sandbox subdomain is a separate environment requiring its own OAuth client registration.
// Inbound webhook payload (new ticket)
{ "ticket_id": "string", "subject": "string", "description": "string",
"requester_email": "string", "created_at": "ISO8601",
"X-Zendesk-Webhook-Signature": "string" }
// Outbound API calls from automation
PUT /api/v2/tickets/{ticket_id}
body: { tags: [...], priority: "string", group_id: integer }
POST /api/v2/tickets/{ticket_id}/comments
body: { body: "string", public: true }Notion
Knowledge base queried by both the Ticket Classification Agent (to confirm FAQ coverage exists) and the First Response Drafting Agent (to retrieve article content for the reply). Integration uses an internal Notion integration token scoped to the FAQ database only.
Auth method
Notion Internal Integration Token. Create the integration at https://www.notion.so/my-integrations and share the target FAQ database with the integration. Store the token as NOTION_API_TOKEN in the credential store.
Required scopes
read_content (no write permission required for this integration)
Webhook / trigger setup
Notion does not support outbound webhooks. The automation platform must make synchronous GET requests to the Notion API when triggered by the Zendesk webhook. No polling is required.
Required configuration
FAQ database ID stored as NOTION_FAQ_DB_ID in the credential store. Database must have the following property columns: Title (title type), Category (select: faq, billing, technical, escalation), Keywords (rich_text), Article_Body (rich_text), Last_Updated (date). Query filter uses Category = faq AND Keywords contains {extracted_keyword}. Do not hardcode the database ID.
Rate limits
Notion API: 3 requests/second average, burst to 90 requests/minute. At current volume (220 tickets/month, ~7.3/day), no throttling is needed. Implement exponential backoff on 429 responses starting at 1 second, max 3 retries.
Constraints
Notion API version header required: Notion-Version: 2022-06-28. Rich text blocks must be concatenated client-side before passing to the drafting agent. Maximum block response per page: 100 blocks; pagination cursor must be handled if articles exceed this limit.
// Query request
POST https://api.notion.com/v1/databases/{NOTION_FAQ_DB_ID}/query
Headers: { Authorization: Bearer {NOTION_API_TOKEN},
Notion-Version: "2022-06-28" }
Body: { filter: { and: [
{ property: "Category", select: { equals: "faq" } },
{ property: "Keywords", rich_text: { contains: "{keyword}" } }
] } }
// Response (relevant fields)
{ results: [ { id: "page_id", properties: {
Title: { title: [ { plain_text: "string" } ] },
Article_Body: { rich_text: [ { plain_text: "string" } ] }
} } ] }HubSpot
Customer contact lookup and activity note creation performed by the Escalation and Logging Agent after every ticket reply or human handoff. Contact is matched by requester email. A new contact is created if no match is found.
Auth method
HubSpot Private App token (recommended over legacy API keys). Create a private app in HubSpot > Settings > Integrations > Private Apps. Store the token as HUBSPOT_PRIVATE_APP_TOKEN in the credential store. No OAuth redirect flow required for server-side automation.
Required scopes
crm.objects.contacts.read crm.objects.contacts.write crm.objects.notes.write crm.objects.notes.read
Webhook / trigger setup
HubSpot is not a trigger source in this automation. The orchestration layer calls HubSpot synchronously after Zendesk reply confirmation. No inbound webhook configuration required.
Required configuration
Contact lookup uses the v3 search API filtered by email property. Note association uses the HubSpot engagements v3 endpoint. HubSpot portal ID stored as HUBSPOT_PORTAL_ID. Custom note body template stored in the orchestration layer environment variables, not hardcoded. If contact is not found, create contact with email and source = support_automation before associating the note.
Rate limits
HubSpot API (Starter): 100 requests/10 seconds, 250,000 requests/day. At 220 tickets/month, this is well within limits. No throttling needed. Retry on 429 with a 10-second wait.
Constraints
HubSpot deduplication on contact creation is by email; ensure the requester email from Zendesk is lowercased and trimmed before lookup to avoid duplicate records. Note body must be plain text or basic HTML; do not pass raw Notion rich_text blocks directly.
// Contact lookup
POST https://api.hubapi.com/crm/v3/objects/contacts/search
Body: { filterGroups: [ { filters: [ {
propertyName: "email", operator: "EQ",
value: "{requester_email}" } ] } ],
properties: ["hs_object_id", "firstname", "lastname", "email"] }
// Note creation
POST https://api.hubapi.com/crm/v3/objects/notes
Body: { properties: {
hs_note_body: "string",
hs_timestamp: "ISO8601" },
associations: [ { to: { id: "{contact_id}" },
types: [ { associationCategory: "HUBSPOT_DEFINED",
associationTypeId: 202 } ] } ] }Slack
Receives structured escalation alert messages posted by the Escalation and Logging Agent for any ticket classified as urgent or escalation. Uses a Bot Token posted to a named channel. No inbound messages are read.
Auth method
Slack OAuth 2.0 Bot Token. Create a Slack App at api.slack.com/apps. Install to workspace and store the Bot User OAuth Token as SLACK_BOT_TOKEN in the credential store.
Required scopes
chat:write chat:write.public channels:read
Webhook / trigger setup
No inbound webhook from Slack. The automation calls the Slack Web API chat.postMessage method. The target channel ID must be stored as SLACK_ESCALATION_CHANNEL_ID in the credential store, not hardcoded as a channel name. Confirm the channel ID with the support team lead before go-live.
Required configuration
Escalation message template must include: ticket_id, requester_email, category label, confidence_score, Zendesk ticket URL (constructed as https://{ZENDESK_SUBDOMAIN}.zendesk.com/agent/tickets/{ticket_id}), and the on-call agent mention using their Slack member ID stored as SLACK_ONCALL_MEMBER_ID. Use Slack Block Kit layout for structured formatting. Do not use plain text only.
Rate limits
Slack Web API: 1 request/second per method (Tier 3, chat.postMessage). At current escalation volume (estimate 20 to 30 urgent tickets/month), no throttling is needed. Implement 1-second sleep between consecutive posts if batch processing is ever introduced.
Constraints
Bot must be invited to the target channel before messages can be posted. Block Kit JSON payload must not exceed 3,000 characters per block. Do not post PII beyond requester email and ticket subject into the Slack message body.
// chat.postMessage call
POST https://slack.com/api/chat.postMessage
Headers: { Authorization: Bearer {SLACK_BOT_TOKEN} }
Body: { channel: "{SLACK_ESCALATION_CHANNEL_ID}",
blocks: [
{ type: "section", text: { type: "mrkdwn",
text: ":rotating_light: *Escalation: Ticket #{ticket_id}*" } },
{ type: "section", fields: [
{ type: "mrkdwn", text: "*Category:* {category}" },
{ type: "mrkdwn", text: "*Confidence:* {confidence_score}" },
{ type: "mrkdwn", text: "*Requester:* {requester_email}" },
{ type: "mrkdwn", text: "*Link:* {zendesk_ticket_url}" } ] },
{ type: "section", text: { type: "mrkdwn",
text: "Assigned to <@{SLACK_ONCALL_MEMBER_ID}>" } }
] }Gmail
Fallback send channel used by the First Response Drafting Agent when the Zendesk reply API returns a non-recoverable error after retries. Sends the drafted reply directly from the support Gmail address to the requester email.
Auth method
OAuth 2.0 with Google Workspace. Register an OAuth 2.0 client in Google Cloud Console (project scoped to the support workspace). Store client_id, client_secret, and refresh_token as GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, GMAIL_REFRESH_TOKEN. Alternatively configure a service account with domain-wide delegation impersonating the support inbox address.
Required scopes
https://www.googleapis.com/auth/gmail.send
Webhook / trigger setup
Gmail is triggered only as a fallback action, never as a primary trigger. No inbound Gmail monitoring is configured in this automation (Zendesk is the sole trigger source). Gmail Push notifications (Pub/Sub) are not required.
Required configuration
Support inbox address stored as GMAIL_FROM_ADDRESS. Reply-To header must be set to the same address. Subject line prefix must match the original ticket subject. Message body is the same drafted reply payload already constructed by the First Response Drafting Agent. Log the fallback send event to HubSpot using the same note creation flow so the activity is not silently lost.
Rate limits
Gmail API send quota: 250 quota units/second per user, 1 billion quota units/day. At 220 tickets/month this is trivially within limits. The fallback path should be rare; no throttling configuration required.
Constraints
Gmail API requires the message to be base64url-encoded RFC 2822 format. The orchestration layer must handle encoding before the API call. Do not send attachments via the fallback path. If Gmail send also fails, the error must be logged and a Slack alert fired; do not silently drop the message.
// Gmail send (fallback)
POST https://gmail.googleapis.com/gmail/v1/users/me/messages/send
Headers: { Authorization: Bearer {access_token} }
Body: { raw: "{base64url_encoded_RFC2822_message}" }
// RFC 2822 message structure (pre-encoding)
From: {GMAIL_FROM_ADDRESS}
To: {requester_email}
Subject: Re: {original_ticket_subject}
Reply-To: {GMAIL_FROM_ADDRESS}
Content-Type: text/plain; charset=UTF-8
{drafted_reply_body}Integration and API SpecPage 2 of 4
FS-DOC-05Technical
03Field mappings between tools
The tables below document the exact field-level mappings at each agent handoff point. Source and destination field names are given in monospace as they appear in each tool's API response or request body. All mappings must be implemented exactly as specified; do not alias or rename fields in transit.
Handoff 1: Zendesk webhook payload to Ticket Classification Agent
Source tool
Source field
Destination tool
Destination field
Zendesk
ticket.id
Classification Agent
ticket_id
Zendesk
ticket.subject
Classification Agent
subject
Zendesk
ticket.description
Classification Agent
body
Zendesk
ticket.requester.email
Classification Agent
requester_email
Zendesk
ticket.created_at
Classification Agent
received_at
Handoff 2: Ticket Classification Agent output to First Response Drafting Agent
Source tool
Source field
Destination tool
Destination field
Classification Agent
ticket_id
Drafting Agent
ticket_id
Classification Agent
category
Drafting Agent
intent_category
Classification Agent
confidence_score
Drafting Agent
confidence_score
Classification Agent
extracted_keyword
Drafting Agent
notion_query_keyword
Classification Agent
requester_email
Drafting Agent
requester_email
Classification Agent
subject
Drafting Agent
original_subject
Handoff 3: Notion API response to First Response Drafting Agent
Source tool
Source field
Destination tool
Destination field
Notion
results[0].properties.Title.title[0].plain_text
Drafting Agent
article_title
Notion
results[0].properties.Article_Body.rich_text[*].plain_text
Drafting Agent
article_body_concatenated
Notion
results[0].properties.Category.select.name
Drafting Agent
article_category
Notion
results[0].properties.Last_Updated.date.start
Drafting Agent
article_last_updated
Handoff 4: First Response Drafting Agent output to Zendesk reply and tag write
Source tool
Source field
Destination tool
Destination field
Drafting Agent
drafted_reply_body
Zendesk
comment.body
Drafting Agent
intent_category
Zendesk
tags[]
Drafting Agent
priority_level
Zendesk
priority
Drafting Agent
routing_group_key
Zendesk
group_id
Drafting Agent
ticket_id
Zendesk
ticket.id (URL param)
Handoff 5: Escalation and Logging Agent to HubSpot note creation
Source tool
Source field
Destination tool
Destination field
Zendesk (via agent context)
requester_email
HubSpot
contact.properties.email (lookup)
Zendesk (via agent context)
ticket_id
HubSpot
hs_note_body (embedded)
Classification Agent
category
HubSpot
hs_note_body (embedded)
Drafting Agent
drafted_reply_body (truncated 500 chars)
HubSpot
hs_note_body (embedded)
System
ISO8601 timestamp at send
HubSpot
hs_timestamp
Handoff 6: Escalation and Logging Agent to Slack alert (escalation tickets only)
Source tool
Source field
Destination tool
Destination field
Zendesk (via agent context)
ticket_id
Slack Block Kit
blocks[0].text.text (ticket number)
Classification Agent
category
Slack Block Kit
blocks[1].fields[0].text
Classification Agent
confidence_score
Slack Block Kit
blocks[1].fields[1].text
Zendesk (via agent context)
requester_email
Slack Block Kit
blocks[1].fields[2].text
Constructed URL
zendesk_ticket_url
Slack Block Kit
blocks[1].fields[3].text
Credential store
SLACK_ONCALL_MEMBER_ID
Slack Block Kit
blocks[2].text.text (mention)
Integration and API SpecPage 3 of 4
FS-DOC-05Technical
04Build stack and orchestration
Orchestration layout
One workflow per agent: Workflow-01 (Ticket Classification Agent), Workflow-02 (First Response Drafting Agent), Workflow-03 (Escalation and Logging Agent). Workflows are chained in sequence via internal event passing; Workflow-01 emits a classification result event consumed by Workflow-02. Workflow-02 emits a reply-sent confirmation event consumed by Workflow-03. All three workflows share a single credential store; no credentials are duplicated across workflows.
Agent 1 trigger mechanism
Webhook (push). Zendesk fires an HTTPS POST to the orchestration platform's inbound webhook URL the moment a new ticket is created. The webhook signature (HMAC-SHA256, header X-Zendesk-Webhook-Signature) must be validated against ZENDESK_WEBHOOK_SECRET before any processing begins. Invalid signatures must return HTTP 401 and halt the workflow.
Agent 2 trigger mechanism
Internal event (chained). Workflow-02 is triggered by the classification result event emitted by Workflow-01 when confidence_score meets or exceeds the configured auto-reply threshold. The threshold value is stored as AUTO_REPLY_THRESHOLD in the credential store and must not be hardcoded. Below-threshold events route to the Zendesk low-confidence queue action and terminate Workflow-02.
Agent 3 trigger mechanism
Internal event (chained). Workflow-03 is triggered by the reply-sent confirmation event from Workflow-02, OR by the low-confidence routing confirmation event from Workflow-01 (for tickets entering the human review queue). Either path must guarantee Workflow-03 fires so that every ticket receives a HubSpot log entry regardless of whether an auto-reply was sent.
Retry configuration
All HTTP calls implement exponential backoff: initial wait 1 second, multiplier 2x, maximum retries 3, maximum wait 16 seconds. 4xx errors (except 429) are not retried; they are routed to the error handler. 429 and 5xx errors trigger the retry sequence. After 3 failed retries, the workflow emits an error event and a Slack alert is fired to SLACK_ALERTS_CHANNEL_ID.
Confidence threshold
AUTO_REPLY_THRESHOLD is stored in the credential store as a decimal (default: 0.82). Adjustable by the FullSpec team without a code deployment. The Classification Agent must return a numeric confidence_score between 0 and 1 on every run.
Credential store contents (all secrets loaded at runtime from the platform credential store; none may appear in workflow code, environment files checked into version control, or log output):
Credential store: all values injected at runtime; never hardcoded in workflow logic
# Zendesk
ZENDESK_SUBDOMAIN=string # e.g. yourcompany
ZENDESK_OAUTH_CLIENT_ID=string
ZENDESK_OAUTH_CLIENT_SECRET=string
ZENDESK_OAUTH_REFRESH_TOKEN=string
ZENDESK_WEBHOOK_SECRET=string # HMAC-SHA256 shared secret for signature validation
ZENDESK_GROUP_ID_FAQ=integer # Zendesk group ID for FAQ auto-resolved queue
ZENDESK_GROUP_ID_HUMAN=integer # Zendesk group ID for low-confidence human queue
ZENDESK_GROUP_ID_ESCALATION=integer # Zendesk group ID for escalation queue
# Notion
NOTION_API_TOKEN=string # Internal integration token
NOTION_FAQ_DB_ID=string # 32-char Notion database ID
# HubSpot
HUBSPOT_PRIVATE_APP_TOKEN=string
HUBSPOT_PORTAL_ID=integer
# Slack
SLACK_BOT_TOKEN=string # xoxb- prefixed Bot User OAuth Token
SLACK_ESCALATION_CHANNEL_ID=string # C-prefixed channel ID (not channel name)
SLACK_ONCALL_MEMBER_ID=string # U-prefixed Slack member ID for @mention
SLACK_ALERTS_CHANNEL_ID=string # Separate channel for automation error alerts
# Gmail (fallback)
GMAIL_CLIENT_ID=string
GMAIL_CLIENT_SECRET=string
GMAIL_REFRESH_TOKEN=string
GMAIL_FROM_ADDRESS=string # e.g. support@yourcompany.com
# Orchestration
AUTO_REPLY_THRESHOLD=0.82 # Decimal 0-1; classification confidence floor
ENVIRONMENT=production # or sandbox
05Error handling and retry logic
Unhandled exceptions must never fail silently. Every failure path must produce a logged error record in the orchestration platform and, for customer-facing failures (reply not sent), fire a Slack alert to SLACK_ALERTS_CHANNEL_ID so the support team can intervene manually.
Integration
Scenario
Required behaviour
Zendesk (inbound webhook)
Webhook signature validation fails (HMAC mismatch)
Return HTTP 401 immediately. Halt workflow. Log event with raw header values (excluding secret). Fire Slack alert to SLACK_ALERTS_CHANNEL_ID. Do not process payload.
Zendesk (inbound webhook)
Webhook payload missing required field (ticket.id, description, or requester.email)
Return HTTP 200 to Zendesk (prevent retry storm). Log malformed payload. Skip workflow execution. Fire Slack alert. Manual review required.
Zendesk (reply API)
POST /tickets/{id}/comments returns 429 (rate limit)
Retry with exponential backoff: 1s, 2s, 4s (max 3 retries). If all retries fail, trigger Gmail fallback send. Log Zendesk rate limit event.
Zendesk (reply API)
POST /tickets/{id}/comments returns 5xx after 3 retries
Trigger Gmail fallback send path. Log failure with ticket_id and HTTP status. Fire Slack alert to SLACK_ALERTS_CHANNEL_ID. Do not drop reply.
Notion (knowledge base query)
Query returns zero results (no matching FAQ article)
Do not auto-reply. Route ticket to ZENDESK_GROUP_ID_HUMAN with tag no-kb-match. Log the extracted_keyword for knowledge base gap tracking. Continue to Workflow-03 for HubSpot logging.
Notion (knowledge base query)
Notion API returns 503 or timeout after 3 retries
Route ticket to ZENDESK_GROUP_ID_HUMAN. Tag as kb-unavailable. Fire Slack alert. Log error. Workflow-03 must still execute for HubSpot logging.
HubSpot (contact lookup)
No contact found matching requester_email
Create a new HubSpot contact with email and source=support_automation. Proceed with note creation on the new contact. Log new-contact creation event for post-launch deduplication review.
HubSpot (note creation)
POST to /crm/v3/objects/notes returns 4xx (except 429) after contact creation
Log the error with ticket_id, contact_id, and HTTP status. Do not retry 4xx (except 429). Fire Slack alert to SLACK_ALERTS_CHANNEL_ID. Manual HubSpot log required.
HubSpot (note creation)
POST returns 429 or 5xx
Retry with exponential backoff: 10s, 20s, 40s (max 3 retries, respecting HubSpot's 10-second rate window). If all retries fail, log error and fire Slack alert.
Slack (escalation alert)
chat.postMessage returns 4xx (invalid channel or token)
Log error with HTTP response body. Do not retry 4xx. Fire a secondary alert attempt to SLACK_ALERTS_CHANNEL_ID. If that also fails, write error to orchestration platform log and surface in dashboard. Never drop silently.
Gmail (fallback send)
Gmail API send fails after Zendesk primary failure
Log error with ticket_id and requester_email. Fire Slack alert to SLACK_ALERTS_CHANNEL_ID. Mark ticket in Zendesk with tag reply-failed and assign to ZENDESK_GROUP_ID_HUMAN for immediate manual reply. PII must not appear in log body.
Classification Agent (AI)
confidence_score not returned or outside 0 to 1 range
Treat as below-threshold. Route to ZENDESK_GROUP_ID_HUMAN with tag classification-error. Log the raw AI response. Workflow-03 must still execute. Do not auto-reply under any circumstance when confidence_score is absent or malformed.
Integration and API SpecPage 4 of 4