Back to Support Ticket Triage & Routing

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

Support Ticket Triage & Routing

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

This document specifies the API contracts, authentication methods, field mappings, and error handling logic required to build and deploy the Support Ticket Triage & Routing automation. It is written for the FullSpec development team and any infrastructure engineers who will configure credentials, monitor integrations, and troubleshoot live data flows. The FullSpec team owns all build, testing, and production deployment. You will confirm API access levels, provide test credentials, and validate field mappings against your live Zendesk, Slack, and HubSpot instances before go-live.

01Tool inventory

Tool
Role
Auth Method
Min Plan
Used by Agents
Zendesk
Ticket source and destination; central helpdesk record
OAuth 2.0 + API token
Team plan ($49/user/month)
Ticket Analyzer, Smart Router
Slack
Team notifications and routing alerts
OAuth 2.0 + Incoming Webhook
Free or Pro ($6.67/user/month)
Smart Router
HubSpot
CRM context and triage decision logging
OAuth 2.0 + Private App Token
Free CRM or Pro ($45/month)
Smart Router
Gmail
Email ticket ingestion and forwarding
OAuth 2.0
Standard Google Workspace
Ticket Analyzer
Workflow Automation Platform
Orchestration, agent execution, and state management
API key (internal to platform)
Starter plan ($150/month suggested)
Both agents, all integrations
Zendesk API token and Slack webhook credentials must be rotated every 90 days and stored in a credential manager with audit logging. OAuth tokens for Zendesk, HubSpot, and Gmail must be refreshed automatically; never store refresh tokens in plaintext. All integrations require TLS 1.2 or higher for data in transit.

02Per-tool integration detail

Zendesk

Primary helpdesk platform. Tickets are ingested via webhook on creation or update, and categorization, priority tags, and assignment are written back via REST API.

Auth Method
OAuth 2.0 (preferred) or API token with user permissions for ticket read/write/tag
Required Scopes
tickets:read, tickets:write, ticket_fields:read, users:read, ticket_comments:create
Webhook Setup
Trigger on ticket.created and ticket.updated events. Webhook URL must be HTTPS and accept JSON payload with ticket ID, status, requester email, subject, and description. Include a shared secret (HMAC-SHA256) for signature verification.
Required Configuration
Create custom ticket fields: category_tag (dropdown), priority_level (select: low/normal/high), assigned_queue (text), sla_deadline (date). Ensure support agents have permission to view but not edit these fields (read-only or automation-only write).
Rate Limits
200 requests per minute (API tier dependent). Queue outbound API calls at 10 per second to avoid burst throttling. Implement exponential backoff (1s, 2s, 4s, 8s) on 429 responses.
Constraints
Ticket body is limited to 40,000 characters. Attachments are not parsed by the AI agent; only text fields (subject, description, custom fields) are analyzed. Zendesk custom fields must exist before automation runs; no dynamic field creation.
// Inbound Webhook Payload (on ticket creation)
{
  ticket_id: 12345,
  requester_email: 'customer@example.com',
  subject: 'Payment not processing',
  description: 'I tried to upgrade my account but my card was declined...',
  created_at: '2024-03-14T09:30:00Z',
  status: 'new',
  custom_fields: { ... }
}
// Outbound API Call (write tags and assignment)
PUT /api/v2/tickets/12345
{
  custom_fields: [
    { id: 123456, value: 'billing' },
    { id: 123457, value: 'high' },
    { id: 123458, value: 'billing_queue' },
    { id: 123459, value: '2024-03-14T11:30:00Z' }
  ],
  assignee_id: 789456,
  status: 'open'
}
Slack

Real-time team notification of new ticket assignment. A single Incoming Webhook URL posts formatted messages to a designated support channel or user direct message.

Auth Method
Incoming Webhook URL (one per channel or user); no OAuth required for webhook posts
Required Scopes
Not applicable. Webhook token is pre-scoped to post messages to the specified channel only. For optional reply interactivity (buttons), add scope chat:write
Webhook Setup
Create one Incoming Webhook per notification destination (e.g. #support-billing, #support-technical, @alice). Store webhook URL securely. Webhook posts must include thread_ts if replying to a thread. Slack enforces 1 webhook URL per channel; reuse same URL for multiple messages to the same channel.
Required Configuration
Message block kit format: use text blocks for summary, context blocks for metadata (priority, SLA deadline, customer name). Include a 'View in Zendesk' button with link to ticket. Example: /zendesk/tickets/{ticket_id}. Test webhook connectivity on deploy.
Rate Limits
1 message per second per webhook URL. Batch multiple updates into a single message thread if possible. If posting to 5 different channels, stagger requests across 5 seconds minimum.
Constraints
Message text limited to 4,000 characters. Do not @mention users in message body; use user_id in block kit for interaction. Webhook expires if not used for 30 days; monitor and refresh quarterly. Slack does not accept HTML; use markdown or block kit only.
// Incoming Webhook POST (send notification)
POST https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX
{
  blocks: [
    {
      type: 'section',
      text: { type: 'mrkdwn', text: '🆕 *New High-Priority Ticket*\nBilling Issue - Payment Failed' }
    },
    {
      type: 'context',
      elements: [
        { type: 'mrkdwn', text: 'Customer: alice@customer.com | SLA: 1 hour' }
      ]
    },
    {
      type: 'actions',
      elements: [
        {
          type: 'button',
          text: { type: 'plain_text', text: 'Open in Zendesk' },
          url: 'https://yourcompany.zendesk.com/agent/tickets/12345'
        }
      ]
    }
  ]
}
HubSpot

CRM logging and customer context. Triage decision (category, priority, assigned queue) is logged to the contact record for reporting and future reference.

Auth Method
OAuth 2.0 or Private App Token (API key with scope: crm.objects.contacts.write, crm.objects.contacts.read)
Required Scopes
crm.objects.contacts.read, crm.objects.contacts.write, crm.objects.deals.read (optional if linking to deal), crm.lists (optional for automation triggers)
Webhook Setup
Not used for inbound webhooks in this integration. HubSpot is write-only. Create a custom activity type 'ticket_triage_log' if desired for activity timeline. Configure activity payload: ticket_id, category, priority, assigned_queue, timestamp.
Required Configuration
Custom contact properties required: last_ticket_category (single-line text), last_ticket_priority (dropdown: low/normal/high), last_assigned_support_queue (single-line text), ticket_triage_count (number). Map Zendesk ticket requester email to HubSpot contact email for upsert logic.
Rate Limits
10 requests per second standard, 100 per 10 seconds in burst. Contact update calls (PATCH /crm/v3/objects/contacts/{id}) are counted individually. If bulk-updating, batch up to 100 contacts per request.
Constraints
Contact must exist in HubSpot before triage log is written. Use email address as lookup key; if no match, create contact first via POST /crm/v3/objects/contacts. Custom property values are validated by type (text length, dropdown options). No direct write to deal or pipeline without deal ID lookup first.
// Lookup Contact by Email
GET /crm/v3/objects/contacts?limit=1&after=0&properties=email&filterGroups=[{filters:[{propertyName:'email',operator:'EQ',value:'customer@example.com'}]}]
// Response
{
  results: [
    {
      id: '456789',
      properties: { email: 'customer@example.com', firstname: 'Alice', lastname: 'Smith' }
    }
  ]
}
// Update Contact with Triage Data
PATCH /crm/v3/objects/contacts/456789
{
  properties: {
    last_ticket_category: 'billing',
    last_ticket_priority: 'high',
    last_assigned_support_queue: 'billing_queue',
    ticket_triage_count: 3
  }
}
Gmail

Email ticket ingestion. Support tickets arriving via email are forwarded to a shared mailbox or label, then parsed by the automation. Subject and body are extracted and sent to the Ticket Analyzer.

Auth Method
OAuth 2.0 (service account or user account with delegated authority). Scopes: gmail.readonly, gmail.modify
Required Scopes
gmail.readonly (read messages), gmail.modify (mark as read, add labels), gmail.labels.readonly (list labels)
Webhook Setup
Set up Gmail push notifications (watch) on the support inbox label. Webhook endpoint receives push event with message ID; polling API then retrieves full message. Alternatively, poll every 5 minutes for messages with label:new OR label:unread in support mailbox.
Required Configuration
Create Gmail label 'support/new-tickets' for incoming support emails. Configure email filter rule to apply this label on arrival. Automation watches this label, retrieves full message (including MIME body), parses to-header for team inbox, and extracts subject + body text. Mark message as read after successful ingestion.
Rate Limits
1,000 requests per minute per user. Push notifications (watch) have no request quota; polling every 5 minutes uses 288 requests/day, well below limit. Use batch API (batchGet) if retrieving multiple messages in sequence.
Constraints
Only plaintext and basic HTML are parsed; rich formatting is stripped. Attachments are not downloaded (only metadata). Max message size is 25MB (platform limit); larger emails may time out. Service account must have folder delegation to support mailbox; cannot use personal account without explicit access grant.
// Watch Request (push notification setup)
POST /gmail/v1/users/support@yourcompany.com/watch
{
  topicName: 'projects/yourproject/topics/gmail-support',
  labelIds: ['Label_1']  // 'support/new-tickets' label ID
}
// Get Message (on push event)
GET /gmail/v1/users/support@yourcompany.com/messages/15e8d5f3e9b1a2c4?format=full
// Response (excerpt)
{
  id: '15e8d5f3e9b1a2c4',
  payload: {
    headers: [
      { name: 'From', value: 'customer@example.com' },
      { name: 'Subject', value: 'Urgent: Payment not processing' },
      { name: 'Date', value: 'Thu, 14 Mar 2024 09:30:00 +0000' }
    ],
    parts: [
      {
        mimeType: 'text/plain',
        body: { data: 'Base64-encoded message body...' }
      }
    ]
  }
}
Integration and API SpecPage 1 of 3
FS-DOC-05Technical

03Field mappings between tools

The following tables specify how data flows between agents and tools. Each handoff includes the source field name, the transformation applied, and the destination field name in the receiving system.

Source Tool
Source Field
Destination Tool
Destination Field
Transformation
Zendesk (webhook)
ticket.description
Ticket Analyzer Agent
(memory input)
Raw text; no change. Max 40,000 chars.
Zendesk (webhook)
ticket.subject
Ticket Analyzer Agent
(memory input)
Concatenated with description for NLP analysis.
Zendesk (webhook)
ticket.requester.email
Ticket Analyzer Agent
(memory input)
Stored for HubSpot contact lookup downstream.
Ticket Analyzer Agent
detected_category
Smart Router Agent
issue_category
Enum: billing, technical, account_access, feature_request, complaint. Passed as JSON key to routing rule engine.
Ticket Analyzer Agent
priority_score (0-1.0)
Smart Router Agent
priority_input
Converted to priority_level: low (0-0.33), normal (0.34-0.66), high (0.67-1.0).
Ticket Analyzer Agent
sentiment_label
Smart Router Agent
customer_sentiment
Enum: positive, neutral, negative. Used as routing override flag (negative + high priority = escalate).
Smart Router Agent
assigned_queue_id
Zendesk (API update)
custom_field: assigned_queue
Zendesk queue ID (integer) converted to queue name string (e.g. 'billing_queue'). Stored in read-only field for audit.
Smart Router Agent
assigned_agent_id
Zendesk (API update)
assignee_id
Zendesk agent user ID (integer). Standard Zendesk ticket assignment field.
Smart Router Agent
priority_level
Zendesk (API update)
custom_field: priority_level
Enum (low/normal/high) written as custom field value. Also used to set Zendesk ticket.priority if enabled.
Smart Router Agent
sla_deadline (ISO 8601)
Zendesk (API update)
custom_field: sla_deadline
Calculated from priority and SLA minutes (high=1hr, normal=4hr, low=24hr). Stored as UTC datetime string.
Zendesk (API response)
ticket.id
Slack Notification
Hyperlink in button URL
Integer ticket ID interpolated into Zendesk URL: https://yourcompany.zendesk.com/agent/tickets/{id}
Zendesk (API response)
ticket.requester.name
Slack Notification
Context block text
Customer name displayed as 'Customer: [name]' for human context in Slack message.
Smart Router Agent
assigned_agent_email
Slack Notification
Webhook destination
If routing to individual agent: fetch agent email from Zendesk API, then look up Slack user_id via slack.users.lookupByEmail (or send to agent DM webhook). If routing to queue: use queue channel webhook URL.
Ticket Analyzer Agent
category
HubSpot Contact
last_ticket_category
String (billing, technical, etc.). Upsert on contact email match.
Smart Router Agent
priority_level
HubSpot Contact
last_ticket_priority
Enum dropdown (low/normal/high). Updated on every ticket triage.
Smart Router Agent
assigned_queue_name
HubSpot Contact
last_assigned_support_queue
String (billing_queue, technical_queue, etc.). Stored for reporting and customer 360 view.
Integration and API SpecPage 2 of 3
FS-DOC-05Technical

04Build stack and orchestration

Orchestration Platform
Workflow automation tool with multi-agent support, webhook listeners, and REST API client. Must support OAuth 2.0 token refresh, JSON schema validation, and exponential backoff retry logic. Minimum required: conditional branching, loop control, and in-memory state for 30+ fields per execution.
Runtime Environment
Cloud-hosted, autoscaling workers with 2 CPU, 512MB RAM per execution. Execution timeout: 5 minutes per ticket (includes API calls, AI processing, and retries). Concurrent execution: 50 tickets in parallel (QA environment), scaling to 500+ in production.
Credential Store
See code block below. All secrets (API tokens, OAuth refresh tokens, webhook URLs) stored in platform credential manager with encryption at rest (AES-256) and field-level audit logging. Credentials rotated every 90 days via automated CI/CD pipeline.
Logging and Observability
All API calls (request, response, error) logged to platform log sink with full JSON payloads (PII masked: email domain only, no full address). Errors tagged with severity (info, warn, error) and integration name. Dashboards track: API latency p50/p95/p99, error rate per tool, retry rate, and ticket throughput.
Data Residency
Ticket data processed in US region (us-east-1) to comply with SOC 2 and GDPR residency requirements. Secrets and logs encrypted in transit (TLS 1.2+) and at rest. No data cached locally on edge nodes; all state flows through encrypted message queue.
Version Control and Deployment
Automation workflows stored as YAML/JSON in Git repository with full history. Deployments via CI/CD pipeline: code merge to main triggers automated test suite, then blue-green deploy to staging, then manual promotion to production. Rollback: one-click revert to previous stable version within 5 minutes.

Credential store configuration (all values stored in platform secure vault, referenced by variable name in workflow):

Credential Store Reference (production environment). All values encrypted at rest and masked in logs.
// Zendesk Integration
ZENDESK_SUBDOMAIN: 'yourcompany'  // Used to construct API base URL
ZENDESK_API_TOKEN: '****REDACTED****'  // OAuth token or API token; rotated 90 days
ZENDESK_OAUTH_REFRESH_TOKEN: '****REDACTED****'  // If using OAuth; refresh before expiry

// Slack Integration
SLACK_WEBHOOK_SUPPORT_BILLING: 'https://hooks.slack.com/services/T00/B00/XXXX'  // #support-billing channel
SLACK_WEBHOOK_SUPPORT_TECHNICAL: 'https://hooks.slack.com/services/T00/B01/XXXX'  // #support-technical channel
SLACK_WEBHOOK_SUPPORT_ESCALATION: 'https://hooks.slack.com/services/T00/B02/XXXX'  // #support-escalation channel
SLACK_BOT_TOKEN: 'xoxb-****'  // Optional: for slack.users.lookupByEmail API calls

// HubSpot Integration
HUBSPOT_PRIVATE_APP_TOKEN: '****REDACTED****'  // Scopes: crm.objects.contacts.read, crm.objects.contacts.write
HUBSPOT_ACCOUNT_ID: '123456789'  // Used in all API calls

// Gmail Integration
GMAIL_SERVICE_ACCOUNT_JSON: '****REDACTED****'  // Full service account key (encrypted)
GMAIL_DELEGATED_EMAIL: 'support@yourcompany.com'  // Mailbox to monitor
GMAIL_LABEL_ID: 'Label_1'  // ID of 'support/new-tickets' label

// Workflow Automation Platform (Internal)
WORKFLOW_API_KEY: '****REDACTED****'  // For logging, state queries, credential refresh
WORKFLOW_ENVIRONMENT: 'production'  // Enum: staging, production
WORKFLOW_TIMEOUT_SECONDS: 300  // Max execution time per ticket
WORKFLOW_MAX_RETRIES: 3  // Retry failed API calls up to 3 times
WORKFLOW_RETRY_BACKOFF_MS: [1000, 2000, 4000]  // Exponential backoff schedule

05Error handling and retry logic

Integration
Scenario
HTTP Status / Error Type
Required Behaviour
Zendesk webhook listener
Webhook payload arrives with malformed JSON
400 Bad Request or JSON parse error
Log error with ticket ID (if recoverable). Return 400 to Zendesk (do not retry; Zendesk will not resend). Alert ops channel in Slack: 'Malformed webhook from Zendesk detected'.
Zendesk API (read ticket)
API authentication fails (invalid token or expired OAuth)
401 Unauthorized
Refresh OAuth token using stored refresh_token. If refresh fails or token not found, alert ops. Halt execution; do not retry with stale token. Ticket will be retried on next workflow execution.
Zendesk API (write tags/assignment)
Custom field does not exist or field type mismatch (e.g. writing string to numeric field)
400 Bad Request with detail 'Invalid field'
Log full error and ticket ID. Do not retry (user action required). Flag ticket for manual review in 'triage-errors' label in Zendesk. Send alert to Zendesk admin: 'Field mapping error detected, check custom field configuration'.
Zendesk API (write tags/assignment)
Assignee ID is invalid or agent does not exist
422 Unprocessable Entity
Fall back to queue assignment instead of individual agent. Log assignee ID that failed. Retry up to 2 times with alternative queue lookup (query Zendesk API for available queues). If all fail, assign to 'general_queue' and log event.
Zendesk API (any operation)
Rate limit exceeded
429 Too Many Requests; retry-after header present
Extract retry-after value (in seconds) from response header. Wait that duration, then retry up to 3 times using exponential backoff. If 3rd retry also returns 429, queue the entire execution for retry in 60 seconds (backpressure).
Zendesk API (any operation)
Server error or service unavailable
500, 502, 503, 504
Retry up to 3 times with exponential backoff (1s, 2s, 4s). If all retries fail, queue entire execution for retry after 5 minutes. Log error and send digest alert to ops (max 1 per hour per endpoint) to avoid alert spam.
Slack webhook (post notification)
Webhook URL is invalid or expired
404 Not Found or 410 Gone
Log error. Alert ops: 'Slack webhook expired or misconfigured for [channel]'. Do not retry; webhook rotation is manual. Fallback: send digest email to support lead with undelivered notifications.
Slack webhook (post notification)
Webhook request timeout or network error
Timeout (>30s) or connection refused
Retry up to 2 times with exponential backoff (2s, 4s). If both fail, log event and queue for retry in 1 minute. Do not block ticket triage; notification delivery is best-effort (eventual consistency).
Slack webhook (post notification)
Message payload exceeds Slack limits (4000 char text, invalid block syntax)
400 Bad Request or detailed Slack error
Truncate message text to 3900 chars and retry once. If failure persists, simplify block layout (remove optional sections) and retry. If still failing, log and send unformatted plaintext message as fallback.
HubSpot API (contact lookup or update)
Contact email does not match any HubSpot contact (lookup returns 0 results)
200 OK, but empty results array
Create new contact via POST /crm/v3/objects/contacts with email, firstname (if available), lastname, triage data. If creation fails due to duplicate (email exists but lookup missed it), retry lookup with exact match filter. Log discrepancy.
HubSpot API (contact update)
Custom property does not exist or type mismatch
400 Bad Request
Log error and contact ID. Attempt PATCH with only standard Zendesk fields (firstname, phone, notes). If still fails, store triage data in contact notes field as JSON comment instead. Alert HubSpot admin to create missing properties.
HubSpot API (any operation)
Rate limit exceeded (10/sec or 100/10-sec burst)
429 Too Many Requests
Implement token bucket rate limiter at integration layer: max 8 requests per second to HubSpot. If client-side limit reached, queue request for later (in-memory queue, max 100 items). If server returns 429, back off 30 seconds and retry once.
Gmail API (fetch message)
Message ID is invalid or message was deleted before fetch
404 Not Found
Log error and message ID. Do not retry (message is gone). Advance to next message in label. If this is >5% of messages, alert ops: possible label misconfiguration.
Ticket Analyzer Agent (AI model)
Model inference fails (timeout, out of memory, or model error)
Agent throws exception or returns null category
Log full error and ticket content (first 500 chars). Assign default category 'general' and priority 'normal'. Flag ticket for manual review via Zendesk tag 'ai-fallback' and Slack alert: 'AI agent failed on ticket [ID]; manual triage required'.
Smart Router Agent (routing rules engine)
No matching routing rule found for detected category
Router logic returns null or 'no_match'
Log category and ticket ID. Route to 'general_support_queue' with priority set to detected level. Document unmatched category in daily ops report so routing rules can be updated.
All error states must be idempotent: if a request is retried after a partial write (e.g. Zendesk tags were written but Slack notification failed), the retry must not duplicate tags or create orphaned data. Use ticket ID as idempotency key in all stateful operations. Circuit breaker pattern (fail fast if an integration is down for >5 minutes) prevents cascading failures; disable automation for that integration and alert ops.
Integration and API SpecPage 3 of 3

More documents for this process

Every document generated for Support Ticket Triage & Routing.

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