Back to Support Ticket Triage & Routing

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

Developer Handover Pack

Support Ticket Triage & Routing

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

This document gives the FullSpec build team everything needed to configure, connect, and test the Support Ticket Triage & Routing automation from first credential to go-live. It covers the full current-state step map with bottlenecks identified, precise agent specifications with IO contracts, an end-to-end data flow trace, and the recommended build stack. The process owner's role during build is to supply documented routing rules and a labelled ticket export; everything else is handled by FullSpec.

01Process snapshot

Step
Name
Description
1
Check Helpdesk Inbox
Support Agent opens the Zendesk queue and scans for unassigned tickets. Happens multiple times per day to prevent backlog build-up. Time cost: 5 min/ticket batch.
2
Open and Read Each Ticket
Agent opens each new ticket and reads the full message to understand the customer issue, re-reading unclear requests and checking prior history. Time cost: 10 min/ticket.
3 BOTTLENECK
Identify Ticket Category
Agent decides which category the ticket belongs to: billing, technical, account access, or general enquiry. Judgment is inconsistent across team members and slows as queue grows. Time cost: 3 min/ticket.
4 BOTTLENECK
Assign Priority Level
Agent assigns low, normal, high, or urgent priority based on issue type and message cues. No standard rubric means decisions vary by agent. Time cost: 3 min/ticket.
5
Look Up Customer Record
Agent checks HubSpot to retrieve the customer's plan tier, previous tickets, and account status before deciding who should handle the ticket. Time cost: 5 min/ticket.
6 BOTTLENECK
Decide Which Agent to Assign
Team Lead selects the assignee based on category, priority, and current workload. Workload visibility is usually guesswork. Slows or fails when the usual lead is unavailable. Time cost: 4 min/ticket.
7
Manually Assign Ticket in Helpdesk
Team Lead updates the assignee, category tag, and priority field in Zendesk. Mis-clicks require correction later. Time cost: 3 min/ticket.
8
Write Internal Note for Assigned Agent
Team Lead adds a brief internal note summarising the issue and account context. Frequently skipped under high workload, leaving the assigned agent without context. Time cost: 5 min/ticket.
9
Notify Agent of New Assignment
Team Lead sends a Slack or email message to the assigned agent. Missed notifications leave tickets sitting idle. Time cost: 2 min/ticket.
10
Send Acknowledgement to Customer
Support Agent sends a templated reply to the customer confirming receipt and providing an estimated response time. Still sent manually despite being templated. Time cost: 4 min/ticket.
Time cost summary: Total manual time per ticket cycle is 44 minutes. At approximately 180 tickets per month (roughly 45 per week), this equates to 6 hours of manual triage labour every week and approximately 26 hours per 30-day period. Steps 2 through 10 are targeted for automation. Step 1 (inbox check) is replaced by the Zendesk webhook trigger. The one remaining human step is an exception-only review for tickets flagged as low-confidence by the classification agent.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Ticket Classification Agent

Reads the subject line and full body of each new Zendesk ticket, cross-references the customer's CRM record fetched from HubSpot, and applies a trained classification schema to output a category label and a priority score. Handles ambiguous language and multi-issue tickets by selecting the dominant primary intent. Where confidence falls below the defined threshold, the agent flags the ticket for human review rather than writing a speculative classification. Output fields are written directly back to the ticket record in Zendesk before the Routing and Notification Agent fires.

Trigger
New ticket created in Zendesk (webhook) AND HubSpot customer record fetch completed successfully.
Tools
Zendesk (ticket read + field write), HubSpot (contact lookup by email).
Replaces steps
Steps 2, 3, 4, and 5 of the manual process.
Estimated build
10 hours | Complexity: Moderate
// Input
zendesk.ticket.id          : string   // Zendesk ticket ID
zendesk.ticket.subject     : string   // Ticket subject line
zendesk.ticket.body        : string   // Full plain-text ticket body
zendesk.ticket.channel     : string   // email | chat | web_form
zendesk.requester.email    : string   // Customer email address
hubspot.contact.plan_tier  : string   // e.g. Free | Starter | Pro | Enterprise
hubspot.contact.account_status : string // active | churned | trial
hubspot.contact.open_tickets   : integer // Count of currently open tickets
hubspot.contact.recent_ticket_ids : array<string>

// Output
classification.category    : string   // billing | technical | account_access | general
classification.priority    : string   // low | normal | high | urgent
classification.confidence  : float    // 0.0 to 1.0
classification.primary_intent : string // One-sentence summary of dominant issue
classification.flag_for_review : boolean // true if confidence < 0.70

// On low confidence (flag_for_review = true)
zendesk.ticket.tag         : string   // 'triage_review_required'
zendesk.ticket.assignee    : string   // Team Lead queue (manual exception path)
  • Zendesk plan tier required: Suite Team or above (API access to ticket field writes and webhook triggers). Confirm this with the process owner before build starts.
  • HubSpot tier required: Free CRM is sufficient for contact lookup by email via the Contacts API. If the customer email is not found in HubSpot, the agent must proceed with ticket data only and log a 'hubspot_record_not_found' flag on the ticket rather than halting.
  • Classification schema must be finalised before training: the four categories (billing, technical, account_access, general) are assumed from the template. Any additional categories require a revised schema and retraining.
  • Training dataset: a minimum of 100 to 200 historically labelled tickets with confirmed category and priority values must be provided by the process owner. Store labelled set in a version-controlled document (Notion or exported CSV) before the classification agent build begins.
  • Confidence threshold is set to 0.70 by default. Tickets scoring below this value must not receive an automated category or priority write. They are tagged 'triage_review_required' and assigned to the Team Lead queue. The threshold must be configurable without a code deploy.
  • Dedupe behaviour: if the webhook fires more than once for the same ticket ID (Zendesk retry on timeout), the agent must check whether 'classification.category' is already populated. If the field is not empty, skip processing and log a 'duplicate_webhook_skipped' event.
  • Field naming in Zendesk: confirm the exact API field names for category tag and priority before writing. Use 'tags' array for category and the built-in 'priority' enum field (low, normal, high, urgent) rather than custom fields unless the process owner confirms custom fields are in use.
  • Confirm with the process owner before build: which ticket types, if any, must never be auto-classified and must always enter the manual review queue regardless of confidence score.
Routing and Notification Agent

Fires immediately after the Ticket Classification Agent has written category and priority to the Zendesk ticket record. Applies a routing rule table to match the ticket's category and priority combination to the correct agent or specialist queue, updates the Zendesk assignee field, adds a pre-formatted internal context note, sends a Slack direct message to the assigned agent, and dispatches a personalised acknowledgement email to the customer via Gmail. This agent handles all post-classification actions in sequence; if any downstream action fails, the failure is logged and a fallback Slack alert is sent to the Team Lead.

Trigger
Ticket Classification Agent writes classification.category and classification.priority to Zendesk AND classification.flag_for_review = false.
Tools
Zendesk (assignee update + internal note), Slack (DM to assigned agent), Gmail (customer acknowledgement email).
Replaces steps
Steps 6, 7, 8, 9, and 10 of the manual process.
Estimated build
8 hours | Complexity: Moderate
// Input
zendesk.ticket.id          : string
zendesk.ticket.subject     : string
zendesk.requester.email    : string
zendesk.requester.name     : string
classification.category    : string   // billing | technical | account_access | general
classification.priority    : string   // low | normal | high | urgent
classification.primary_intent : string
hubspot.contact.plan_tier  : string
hubspot.contact.open_tickets   : integer
routing_rules_table        : object   // Loaded from Notion or config store at runtime

// Output
zendesk.ticket.assignee_id : string   // Zendesk agent user ID
zendesk.internal_note      : string   // Formatted context note body
slack.dm.recipient         : string   // Slack user ID of assigned agent
slack.dm.message           : string   // Ticket number, category, priority, direct URL
gmail.to                   : string   // Customer email address
gmail.subject              : string   // 'We received your request [Ticket #XXXXX]'
gmail.body                 : string   // Personalised acknowledgement with SLA window

// On routing or notification failure
error_log.event            : string   // 'routing_failed' | 'slack_failed' | 'gmail_failed'
error_log.ticket_id        : string
error_log.timestamp        : datetime
slack.fallback_alert.channel : string // #support-ops or Team Lead DM
  • Routing rules table must exist before this agent can be built. The table maps category-priority combinations to specific Zendesk agent user IDs. If the process owner has not yet documented routing rules, a mapping session is required and build of this agent must be blocked until the table is complete. Store the rules in Notion and load them at runtime via the Notion API or export them to a static config file in the credential store.
  • Slack integration requires the automation platform's bot to be installed in the workspace with the 'chat:write' and 'users:read' OAuth scopes. Confirm Slack user IDs for every agent in the routing table before build. Do not use display names as identifiers.
  • Gmail send must use a shared support mailbox (e.g. support@[YourCompany.com]) authorised via OAuth 2.0. Do not use a personal agent Gmail account. Confirm the mailbox address and OAuth refresh token before build.
  • Acknowledgement email SLA window is priority-driven: urgent = 1 hour, high = 4 hours, normal = 1 business day, low = 2 business days. These values must be confirmed by the process owner and stored as configurable constants, not hardcoded strings.
  • Internal context note template must be version-controlled. The note should include: ticket category, priority, customer plan tier, count of open tickets, primary intent summary, and a timestamp. Do not include raw ticket body text in the note to avoid duplication.
  • Fallback behaviour: if no routing rule matches a category-priority pair (e.g. a new category is added without updating the rules table), the ticket must be assigned to the Team Lead queue, tagged 'routing_rule_missing', and a Slack alert sent to #support-ops. Never leave a ticket unassigned.
  • Round-robin and capacity-based routing are out of scope for the Standard build. If the process owner requires workload-balanced assignment rather than category-based assignment, this must be raised as a scope change before the routing agent build begins.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow with field names at each agent handoff
// ─────────────────────────────────────────────────────────────────
// TRIGGER: New ticket created in Zendesk (any inbound channel)
// ─────────────────────────────────────────────────────────────────
WEBHOOK_PAYLOAD {
  zendesk.ticket.id          : '98432'
  zendesk.ticket.subject     : 'Cannot access my account after password reset'
  zendesk.ticket.body        : '<full plain-text body>'
  zendesk.ticket.channel     : 'email'
  zendesk.ticket.created_at  : '2025-06-03T09:14:22Z'
  zendesk.requester.email    : 'customer@example.com'
  zendesk.requester.name     : 'Alex Rivera'
}

// ─────────────────────────────────────────────────────────────────
// STEP 1: HubSpot contact lookup (by requester email)
// ─────────────────────────────────────────────────────────────────
HubSpot.Contacts.search({
  filterGroups: [{ filters: [{ propertyName: 'email',
                              operator: 'EQ',
                              value: zendesk.requester.email }] }]
})
RETURNS {
  hubspot.contact.id             : 'hs-1029384'
  hubspot.contact.plan_tier      : 'Pro'
  hubspot.contact.account_status : 'active'
  hubspot.contact.open_tickets   : 1
  hubspot.contact.recent_ticket_ids : ['98100', '97881']
}
// If no HubSpot record: set hubspot.contact.plan_tier = 'unknown',
//   log 'hubspot_record_not_found', continue to classification.

// ─────────────────────────────────────────────────────────────────
// AGENT HANDOFF 1: Ticket Classification Agent receives merged payload
// ─────────────────────────────────────────────────────────────────
CLASSIFICATION_INPUT {
  ticket_id        : zendesk.ticket.id
  subject          : zendesk.ticket.subject
  body             : zendesk.ticket.body
  channel          : zendesk.ticket.channel
  requester_email  : zendesk.requester.email
  plan_tier        : hubspot.contact.plan_tier
  account_status   : hubspot.contact.account_status
  open_tickets     : hubspot.contact.open_tickets
}

// Classification model evaluates subject + body + account context
CLASSIFICATION_OUTPUT {
  classification.category       : 'account_access'
  classification.priority       : 'high'
  classification.confidence     : 0.91
  classification.primary_intent : 'Customer locked out after password reset'
  classification.flag_for_review: false
}

// ─────────────────────────────────────────────────────────────────
// CONFIDENCE GATE
// ─────────────────────────────────────────────────────────────────
IF classification.confidence < 0.70 THEN
  zendesk.PUT /tickets/98432 {
    tags: ['triage_review_required'],
    assignee_id: TEAM_LEAD_USER_ID
  }
  LOG 'low_confidence_routed_to_human' -> error_log table
  HALT  // Routing and Notification Agent does not fire
END IF

// ─────────────────────────────────────────────────────────────────
// STEP 2: Write classification fields back to Zendesk ticket
// ─────────────────────────────────────────────────────────────────
Zendesk.PUT /api/v2/tickets/98432 {
  priority : 'high'
  tags     : ['account_access']
  custom_fields: [
    { id: CATEGORY_FIELD_ID, value: 'account_access' },
    { id: CONFIDENCE_FIELD_ID, value: 0.91 }
  ]
}

// Dedupe check: if category field already populated, skip and log
// 'duplicate_webhook_skipped' then HALT

// ─────────────────────────────────────────────────────────────────
// AGENT HANDOFF 2: Routing and Notification Agent receives output
// ─────────────────────────────────────────────────────────────────
ROUTING_INPUT {
  ticket_id        : '98432'
  subject          : zendesk.ticket.subject
  requester_email  : 'customer@example.com'
  requester_name   : 'Alex Rivera'
  category         : 'account_access'
  priority         : 'high'
  primary_intent   : 'Customer locked out after password reset'
  plan_tier        : 'Pro'
  open_tickets     : 1
  routing_rules    : { account_access+high: AGENT_USER_ID_42 }
}

// ─────────────────────────────────────────────────────────────────
// STEP 3: Assign ticket in Zendesk
// ─────────────────────────────────────────────────────────────────
Zendesk.PUT /api/v2/tickets/98432 {
  assignee_id: 'AGENT_USER_ID_42'
}

// ─────────────────────────────────────────────────────────────────
// STEP 4: Add internal context note to ticket
// ─────────────────────────────────────────────────────────────────
Zendesk.POST /api/v2/tickets/98432/comments {
  body   : '[AUTO] Category: Account Access | Priority: High\n
             Plan Tier: Pro | Open tickets: 1\n
             Intent: Customer locked out after password reset\n
             Classified at: 2025-06-03T09:14:35Z'
  public : false
}

// ─────────────────────────────────────────────────────────────────
// STEP 5: Slack DM to assigned agent
// ─────────────────────────────────────────────────────────────────
Slack.POST /api/chat.postMessage {
  channel : 'SLACK_USER_ID_AGENT_42'
  text    : ':ticket: New ticket #98432 assigned to you\n
             Category: Account Access | Priority: High\n
             https://[YourCompany.zendesk.com]/tickets/98432'
}

// ─────────────────────────────────────────────────────────────────
// STEP 6: Customer acknowledgement email via Gmail
// ─────────────────────────────────────────────────────────────────
Gmail.POST /gmail/v1/users/me/messages/send {
  to      : 'customer@example.com'
  subject : 'We received your request [Ticket #98432]'
  body    : 'Hi Alex, thanks for getting in touch. We have received
             your request and our team will respond within 4 hours.
             Reference: #98432.'
}

// ─────────────────────────────────────────────────────────────────
// ON ANY DOWNSTREAM FAILURE (Slack or Gmail)
// ─────────────────────────────────────────────────────────────────
LOG {
  error_log.event     : 'slack_failed' | 'gmail_failed'
  error_log.ticket_id : '98432'
  error_log.timestamp : datetime
}
Slack.POST fallback_alert -> #support-ops | Team Lead DM
// ─────────────────────────────────────────────────────────────────
// END OF AUTOMATED CYCLE
// Total automated elapsed time: target < 90 seconds from webhook
// ─────────────────────────────────────────────────────────────────
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation platform configured with two discrete workflows: one per agent (Ticket Classification Agent and Routing and Notification Agent). Each workflow is independently versioned and testable. A shared credential store holds all API keys and OAuth tokens centrally so that rotating a credential in one place updates both workflows. No platform-specific tooling is assumed at this stage; the architecture is platform-agnostic and can be implemented in any capable orchestration tool.
Webhook configuration
Zendesk outbound webhook fires on ticket creation event (trigger: ticket created, any channel). Webhook URL points to the orchestration layer's inbound endpoint. Payload format: JSON. Authentication: HMAC signature verification using a shared secret stored in the credential store. The orchestration layer must validate the signature on every inbound request and reject payloads that fail validation. Zendesk retry policy: up to 3 retries on timeout; the dedupe guard in the Classification Agent handles duplicate deliveries.
Templating approach
Internal context note and customer acknowledgement email are built from named templates stored as plain-text strings in the credential or config store. Templates use slot variables (e.g. {{ticket_id}}, {{category}}, {{priority}}, {{plan_tier}}, {{sla_window}}) replaced at runtime. SLA window values (urgent = 1 hour, high = 4 hours, normal = 1 business day, low = 2 business days) are stored as a configurable constants object and injected into the template at send time. Template updates must not require a workflow redeploy.
Error logging
All errors, low-confidence flags, duplicate webhook events, missing HubSpot records, and failed downstream actions are written to a Supabase table (schema: event_type, ticket_id, agent_name, error_detail, timestamp, resolved boolean). A Slack alert fires to #support-ops whenever a new error row is inserted. The Team Lead reviews this channel daily. FullSpec will configure the Supabase table, the insert action within each workflow, and the Slack alert during the build phase.
Testing approach
All integrations are first validated in sandbox or test-mode environments before connecting to production. Zendesk sandbox is used for ticket creation and field write tests. HubSpot sandbox contact records are created for plan tier and missing-record scenarios. Slack test workspace (or a #qa-test channel) is used for notification verification. Gmail send is tested to an internal inbox before customer-facing send is enabled. Classification accuracy is validated against the labelled historical ticket dataset before confidence threshold is locked. A parallel run of one week (automation alongside manual triage) is conducted in production before full go-live, with both outputs compared by the Team Lead.
Estimated total build time
Ticket Classification Agent: 10 hours. Routing and Notification Agent: 8 hours. End-to-end integration testing, parallel run setup, and error logging configuration: 6 hours. Total: 24 hours across the 4-week delivery schedule. The template snapshot records 18 hours of core build effort; the additional 6 hours cover QA, parallel run support, and credential validation across all five integrated tools.
Pre-build blockers: three items must be resolved before any build work starts. First, the process owner must supply a routing rules table mapping every category-priority combination to a named Zendesk agent user ID. Second, a labelled export of 100 to 200 historical tickets (with confirmed category and priority) must be available for classification training. Third, Zendesk API credentials (Suite Team tier or above), HubSpot OAuth token, Slack bot OAuth installation, and Gmail OAuth 2.0 authorisation for the shared support mailbox must all be provisioned and handed to the FullSpec team before the Week 2 build start. Any delay to these items delays the corresponding agent build.
Support contact: for any questions about this handover pack or the build, contact the FullSpec team at support@gofullspec.com.
Developer Handover PackPage 4 of 4

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
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View