Back to FAQ & First Response Automation

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

FAQ & First Response Automation

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

This document is the complete technical reference for the FullSpec team building the FAQ and First Response Automation. It covers the current-state step map with bottleneck identification, full specifications for each of the three agents, an end-to-end data flow trace, and the recommended build stack with time estimates. The FullSpec team uses this document to drive every build and integration decision. Your team's responsibility is to confirm credentials, tool tiers, and knowledge base readiness before build begins.

01Process snapshot

Step
Name
Description
1
Monitor Inbox for New Tickets
A support agent checks the shared Zendesk queue at intervals throughout the day. Overnight tickets pile up until the first morning check. Time cost: 10 min/ticket cycle.
2
Read and Classify the Ticket
The agent reads the ticket and mentally decides the category: FAQ, billing, technical, or escalation. No consistent framework is applied. Time cost: 5 min/ticket cycle.
3
Search Help Docs for Relevant Answer
The agent opens Notion and searches for the matching policy or procedure. Disorganised docs mean this regularly runs long. Time cost: 7 min/ticket cycle. BOTTLENECK.
4
Draft Reply Using Help Doc Content
The agent copies the relevant Notion section and personalises it with the customer's name and ticket details. Largely copy-paste but demands attention to avoid errors. Time cost: 8 min/ticket cycle. BOTTLENECK.
5
Apply Tags and Set Ticket Priority
The agent manually applies category tags and sets a priority level in Zendesk. Inconsistent tagging makes reporting unreliable. Time cost: 3 min/ticket cycle.
6
Route Ticket to Correct Team Member
Non-FAQ tickets are re-assigned to the appropriate agent or department inside Zendesk, done from memory without clear routing rules. Time cost: 3 min/ticket cycle.
7
Send First Response to Customer
The agent sends the reply via Zendesk or Gmail and marks the ticket as pending. Average time from receipt to send is 3 to 6 hours during busy periods. Time cost: 2 min/ticket cycle.
8
Log Interaction in HubSpot
The agent adds a note or activity to the customer's HubSpot contact record. This step is frequently skipped when ticket volume is high. Time cost: 4 min/ticket cycle.
9
Notify Team of Urgent Escalations
The agent sends a manual Slack message for urgent tickets. No automated alert means urgent issues can be missed during high-volume periods. Time cost: 3 min/ticket cycle. BOTTLENECK.
Time cost summary: Total manual time per ticket cycle is 45 minutes. At approximately 220 tickets per month (roughly 55 per week), this produces 9 manual hours per week and approximately 39 hours per 30 days. The automation replaces Steps 2, 3, 4, 5, 6, 7, 8, and 9 for FAQ-category tickets above the confidence threshold. Step 9 is replaced entirely across all ticket types. Step 1 is eliminated by the continuous Zendesk webhook trigger. The one remaining human step is manual review of low-confidence tickets flagged by the Classification Agent.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Ticket Classification Agent

Reads each incoming Zendesk ticket body and subject line, identifies the intent category (FAQ, billing, technical, or escalation), and assigns a numerical confidence score between 0 and 1. Tickets scoring above the agreed auto-reply threshold are passed to the First Response Drafting Agent. Tickets scoring below the threshold are tagged and placed in a dedicated human-review queue in Zendesk without any automated reply being sent. This agent is the decision gate for the entire workflow. Estimated build: 14 hours. Complexity: Moderate.

Trigger
New ticket event received from Zendesk webhook (ticket.created)
Tools
Zendesk (read ticket, write tags and priority), Notion (category reference lookup)
Replaces steps
Steps 1, 2, 5, 6 (monitoring, classification, tagging, routing)
Estimated build
14 hours, Moderate complexity
// Input
zendesk.ticket.id          : string
zendesk.ticket.subject     : string
zendesk.ticket.body        : string
zendesk.ticket.requester   : { email: string, name: string }
zendesk.ticket.created_at  : ISO8601 timestamp

// Output
classification.category    : enum(faq | billing | technical | escalation)
classification.confidence  : float (0.00 to 1.00)
classification.priority    : enum(low | normal | high | urgent)
classification.route_to    : string (agent queue name in Zendesk)
classification.flag_human  : boolean (true if confidence < threshold)
zendesk.tags_applied       : array<string>

// On low confidence
zendesk.queue              : 'human-review'
zendesk.internal_note      : 'Low confidence classification: <category> (<score>). Assigned for manual review.'
  • Zendesk plan must be Suite Team or above to support webhook triggers and tag-write API access. Confirm plan tier before build.
  • Notion integration requires a Notion internal integration token with read access to the FAQ knowledge base database. The knowledge base must be fully audited and structured before this agent is built.
  • The confidence threshold value (recommended starting point: 0.80) must be agreed with the support team lead before the agent is deployed. Store the threshold as a configurable environment variable, not hardcoded.
  • Category labels (faq, billing, technical, escalation) must match exactly the Zendesk tag naming convention already in use, or new tags must be created before build.
  • Dedupe behaviour: if a ticket already carries a classification tag from a previous webhook fire, the agent must skip re-classification and exit cleanly to prevent duplicate tagging.
  • Fallback: if the Zendesk API returns an error on tag-write, log to the error table and send a Slack alert to the support team channel; do not fail silently.
  • Confirm with the team lead which ticket types must always be routed to human review regardless of confidence score (for example, legal queries, complaints, or sensitive account issues).
First Response Drafting Agent

Triggers only when the Ticket Classification Agent returns an FAQ category with a confidence score at or above the configured threshold. Queries the Notion knowledge base for the article matching the classified FAQ topic, then combines the retrieved content with the customer's name and specific ticket detail to produce a personalised, on-brand first response. The completed reply is submitted to Zendesk for immediate send, and the ticket is marked as pending. For tickets that required Gmail as the send channel (fallback), the reply is dispatched via the Gmail API. Estimated build: 12 hours. Complexity: Moderate.

Trigger
Ticket Classification Agent output: category = faq AND confidence >= configured threshold
Tools
Notion (knowledge base query), Zendesk (send reply, mark pending), Gmail (fallback send channel)
Replaces steps
Steps 3, 4, 7 (help doc search, reply drafting, first response send)
Estimated build
12 hours, Moderate complexity
// Input
classification.category    : 'faq'
classification.confidence  : float >= threshold
zendesk.ticket.id          : string
zendesk.ticket.body        : string
zendesk.ticket.requester   : { email: string, name: string }
notion.db_id               : string (FAQ knowledge base database ID)

// Notion query
notion.filter              : { property: 'Topic', contains: classification.faq_topic }
notion.result.title        : string
notion.result.body_text    : string (plain text extracted from page blocks)

// Output
reply.body                 : string (personalised, on-brand reply text)
reply.channel              : enum(zendesk | gmail)
zendesk.ticket.status      : 'pending'
zendesk.public_comment     : reply.body
gmail.to                   : zendesk.ticket.requester.email  // fallback only
gmail.subject              : 'Re: ' + zendesk.ticket.subject  // fallback only

// On Notion miss (no matching article)
classification.flag_human  : true
zendesk.queue              : 'human-review'
zendesk.internal_note      : 'No matching Notion article found for topic: <faq_topic>. Routed for manual reply.'
  • Notion database must have a 'Topic' property (select or multi-select type) with values that map to the classification categories used by the Classification Agent. Confirm property names match before build.
  • If the Notion query returns zero results for a classified FAQ topic, the agent must fall back to the human-review queue rather than attempting to generate a reply from no source. This must be tested for every FAQ category during QA.
  • Gmail fallback is triggered only when the Zendesk send API call fails or when the originating ticket arrived via Gmail rather than the Zendesk web widget. Confirm the routing logic with the support team lead.
  • Gmail OAuth 2.0 scopes required: gmail.send and gmail.compose. A service account or delegated admin credential is preferred over a personal OAuth token.
  • Reply tone and brand voice must be confirmed with the support team lead and encoded in the system prompt before build. Provide at least three approved example replies as few-shot examples in the prompt.
  • The agent must not auto-send any reply for ticket categories other than FAQ, even if invoked erroneously. Add a category guard as the first conditional in the workflow.
Escalation and Logging Agent

Runs as a post-send step for every ticket processed by the workflow, regardless of whether a reply was auto-sent or the ticket was routed to human review. Creates an activity note on the matching HubSpot contact record containing the ticket category, the reply text or routing outcome, and the timestamp. For tickets classified as urgent or escalation, the agent also posts a structured Slack message to the designated support channel, tagging the on-call agent with a ticket summary and a direct Zendesk link. Estimated build: 8 hours. Complexity: Simple.

Trigger
First response sent via Zendesk or Gmail, OR ticket routed to human-review queue by Classification Agent
Tools
HubSpot (activity note create, contact match by email), Slack (channel message, user mention)
Replaces steps
Steps 8, 9 (HubSpot logging, urgent escalation Slack alert)
Estimated build
8 hours, Simple complexity
// Input
zendesk.ticket.id          : string
zendesk.ticket.requester   : { email: string, name: string }
zendesk.ticket.subject     : string
classification.category    : enum(faq | billing | technical | escalation)
classification.priority    : enum(low | normal | high | urgent)
reply.body                 : string (or 'Routed to human review' if no auto-reply sent)
reply.sent_at              : ISO8601 timestamp
zendesk.ticket.url         : string (direct link)

// HubSpot output
hubspot.contact.match_by   : zendesk.ticket.requester.email
hubspot.activity.type      : 'NOTE'
hubspot.activity.body      : 'Support ticket received. Category: <category>. Reply sent: <reply.body>. Timestamp: <reply.sent_at>.'
hubspot.contact.action     : enum(append_to_existing | create_new)  // create_new if no email match

// Slack output (urgent or escalation tickets only)
slack.channel              : '#support-escalations'
slack.message              : ':rotating_light: *Urgent ticket* | <zendesk.ticket.url> | Customer: <requester.name> | Subject: <ticket.subject> | Priority: <priority>'
slack.mention              : '@oncall-support',

// On HubSpot API error
error_log.table            : 'automation_errors'
error_log.fields           : { ticket_id, error_code, timestamp, agent: 'EscalationLoggingAgent' }
slack.alert_channel        : '#support-ops-alerts'
  • HubSpot Private App token requires scopes: crm.objects.contacts.read, crm.objects.contacts.write, crm.objects.notes.write. Confirm the HubSpot subscription tier supports Private Apps (Starter or above).
  • Contact matching is by email address only. If the requester email does not exist in HubSpot, a new contact is created rather than failing. Post-launch deduplication review is strongly recommended.
  • Slack app must be installed to the workspace with chat:write and chat:write.public scopes. The target channel (#support-escalations) must be confirmed with the support team lead, including whether the channel is private.
  • The Slack @oncall-support mention must reference a real Slack user group or user handle. Confirm the exact handle before build to avoid silent mention failures.
  • The Slack alert fires for classification.priority = urgent OR classification.category = escalation. Confirm both conditions with the support team lead before wiring the conditional.
  • All HubSpot and Slack API errors must be written to the error log table and trigger a secondary Slack alert to the ops channel (#support-ops-alerts), not the customer-facing escalation channel.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full workflow data flow: trigger to final output, with agent handoff boundaries and exact field names at each stage
// ─────────────────────────────────────────────
// TRIGGER: Zendesk webhook fires on ticket.created
// ─────────────────────────────────────────────
RECEIVE zendesk.webhook.event = 'ticket.created'
  ticket.id          = event.ticket.id
  ticket.subject     = event.ticket.subject
  ticket.body        = event.ticket.description
  ticket.requester   = { email: event.ticket.requester.email, name: event.ticket.requester.name }
  ticket.created_at  = event.ticket.created_at
  ticket.url         = 'https://<subdomain>.zendesk.com/agent/tickets/' + ticket.id

// ─────────────────────────────────────────────
// AGENT HANDOFF 1: Ticket Classification Agent
// ─────────────────────────────────────────────
CALL ClassificationAgent(
  input: { ticket.id, ticket.subject, ticket.body, ticket.requester, ticket.created_at }
)

  // AI prompt receives ticket.subject + ticket.body
  // Notion category reference queried for label validation
  classification.category    = AI_OUTPUT.category    // enum: faq | billing | technical | escalation
  classification.faq_topic   = AI_OUTPUT.faq_topic   // string: matched FAQ topic label
  classification.confidence  = AI_OUTPUT.confidence  // float: 0.00 to 1.00
  classification.priority    = AI_OUTPUT.priority    // enum: low | normal | high | urgent
  classification.route_to    = LOOKUP(category -> zendesk_queue_name)
  classification.flag_human  = (confidence < ENV.CONFIDENCE_THRESHOLD)  // threshold stored as env var

  // Write to Zendesk
  ZENDESK PUT /tickets/{ticket.id}
    tags     += [classification.category, classification.priority]
    assignee  = classification.route_to

// ─────────────────────────────────────────────
// DECISION GATE: confidence threshold check
// ─────────────────────────────────────────────
IF classification.flag_human = true
  ZENDESK PUT /tickets/{ticket.id}
    tags     += ['human-review']
    queue     = 'human-review'
    comment   = INTERNAL_NOTE('Low confidence: ' + classification.category + ' (' + classification.confidence + ')')
  GOTO LoggingAgent  // skip drafting; still log and alert if urgent

// ─────────────────────────────────────────────
// AGENT HANDOFF 2: First Response Drafting Agent
// ─────────────────────────────────────────────
IF classification.category = 'faq' AND classification.flag_human = false
  CALL DraftingAgent(
    input: { ticket.id, ticket.body, ticket.requester, classification.faq_topic, notion.db_id = ENV.NOTION_FAQ_DB_ID }
  )

  // Notion query
  NOTION POST /databases/{notion.db_id}/query
    filter   = { property: 'Topic', select: { equals: classification.faq_topic } }
  notion.article.title     = NOTION_RESULT.properties.Name.title[0].plain_text
  notion.article.body_text = NOTION_RESULT.extract_plain_text(page_blocks)

  IF notion.article = NULL
    classification.flag_human = true
    ZENDESK internal_note = 'No Notion article for topic: ' + classification.faq_topic
    GOTO LoggingAgent

  // AI drafting
  reply.body   = AI_DRAFT(
    system_prompt   = ENV.DRAFT_SYSTEM_PROMPT,
    few_shot        = ENV.APPROVED_EXAMPLES,
    context         = { notion.article.body_text, ticket.requester.name, ticket.body }
  )
  reply.sent_at = NOW()

  // Send reply
  ZENDESK POST /tickets/{ticket.id}/comments
    public  = true
    body    = reply.body
  ZENDESK PUT /tickets/{ticket.id}
    status  = 'pending'

  IF zendesk.send_error = true
    GMAIL POST /users/me/messages/send
      to      = ticket.requester.email
      subject = 'Re: ' + ticket.subject
      body    = reply.body

// ─────────────────────────────────────────────
// AGENT HANDOFF 3: Escalation and Logging Agent
// ─────────────────────────────────────────────
LoggingAgent:
CALL EscalationLoggingAgent(
  input: {
    ticket.id, ticket.requester, ticket.subject, ticket.url,
    classification.category, classification.priority,
    reply.body OR 'Routed to human review',
    reply.sent_at OR NOW()
  }
)

  // HubSpot contact match
  HUBSPOT GET /crm/v3/objects/contacts?email={ticket.requester.email}
  IF hubspot.contact EXISTS
    hubspot.action = 'append_to_existing'
    hubspot.contact_id = hubspot.contact.id
  ELSE
    HUBSPOT POST /crm/v3/objects/contacts
      { email: ticket.requester.email, firstname: ticket.requester.name }
    hubspot.action = 'create_new'
    hubspot.contact_id = NEW_CONTACT.id

  // Create HubSpot note
  HUBSPOT POST /crm/v3/objects/notes
    hs_note_body        = 'Category: ' + classification.category + '. Reply: ' + reply.body + '. Sent: ' + reply.sent_at
    hs_timestamp        = reply.sent_at
  HUBSPOT POST /crm/v3/associations/notes/{note.id}/contacts/{hubspot.contact_id}

  // Slack escalation alert (conditional)
  IF classification.priority = 'urgent' OR classification.category = 'escalation'
    SLACK POST /chat.postMessage
      channel = ENV.SLACK_ESCALATION_CHANNEL  // e.g. '#support-escalations'
      text    = ':rotating_light: *Urgent ticket* | <' + ticket.url + '> | ' + ticket.requester.name + ' | ' + ticket.subject + ' | Priority: ' + classification.priority
      mention = ENV.SLACK_ONCALL_HANDLE       // e.g. '@oncall-support'

// ─────────────────────────────────────────────
// END STATE
// ─────────────────────────────────────────────
  ticket.status      = 'pending' (auto-replied) OR 'open' (human-review queue)
  hubspot.note       = written to contact record
  slack.alert        = sent (urgent/escalation) OR skipped (routine)
  total_elapsed      = < 2 minutes for FAQ auto-reply path
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation platform with one discrete workflow per agent (three workflows total). Each workflow shares a centralised credential store. No build platform is specified at this stage; the FullSpec team selects the appropriate tool based on the confirmed tool tiers and access methods. Workflows are named: wf_ticket_classification, wf_first_response_drafting, wf_escalation_logging.
Webhook configuration
Zendesk outbound webhook configured on the ticket.created event. The webhook POST target is the public endpoint of the orchestration layer. Payload includes: ticket.id, ticket.subject, ticket.description, requester.email, requester.name, created_at. Webhook secret validated via HMAC-SHA256 signature header on every inbound request. Zendesk plan must support outbound webhooks (Suite Team or above).
Templating approach
AI reply drafts are generated using a structured system prompt stored as an environment variable (ENV.DRAFT_SYSTEM_PROMPT). The prompt includes brand voice guidelines and three approved example replies (few-shot examples stored in ENV.APPROVED_EXAMPLES). Notion article body text is injected as the knowledge context block. Customer name and ticket body are injected as user-facing variables. All prompt versions are tracked in a prompt-version log with the date of change and the initiating team member.
Error logging
All agent errors (Zendesk write failures, Notion API misses, HubSpot contact errors, Slack send failures) are written to a dedicated Supabase table named automation_errors. Schema: { id, ticket_id, agent_name, error_code, error_message, timestamp, resolved: boolean }. A secondary Slack alert fires to #support-ops-alerts on any error entry. The FullSpec team reviews the error table weekly during the parallel run period and monthly post-launch.
Testing approach
All agents are built and tested in sandbox environments first. Zendesk sandbox (available on Suite plans) is used for ticket creation and webhook testing. Notion test database (duplicate of production FAQ database) is used for knowledge base queries. HubSpot sandbox account is used for contact and note creation. Slack test channel (#support-automation-test) is used for alert testing. No production data is used until the parallel run phase begins in Week 4.
Estimated total build time
Ticket Classification Agent: 14 hours. First Response Drafting Agent: 12 hours. Escalation and Logging Agent: 8 hours. End-to-end integration testing and QA: 4 hours. Total: 38 hours across a 4-week delivery schedule.
Pre-build blockers: the following must be confirmed before any build work begins. (1) Zendesk plan tier confirmed as Suite Team or above. (2) Notion FAQ knowledge base audited and structured with a 'Topic' property using consistent select values. (3) HubSpot Private App token created with the required scopes. (4) Slack app installed to workspace with bot token and target channel confirmed. (5) Confidence threshold value agreed with the support team lead and documented. (6) List of ticket types that must always route to human review confirmed in writing. Contact FullSpec at support@gofullspec.com to confirm readiness before the build is scheduled.
Component
Tool or Approach
Status
Ticket inbox trigger
Zendesk webhook (ticket.created)
Confirm plan tier
Classification AI
LLM via orchestration layer (model TBC)
To configure
Knowledge base query
Notion API (Internal Integration Token)
Confirm DB structure
Reply send (primary)
Zendesk Tickets API (public comment)
Ready to build
Reply send (fallback)
Gmail API (OAuth 2.0, gmail.send scope)
Confirm credentials
CRM logging
HubSpot CRM API v3 (Private App token)
Confirm scopes
Escalation alert
Slack Web API (chat.postMessage)
Confirm channel + handle
Error logging
Supabase table: automation_errors
Ready to build
Credential store
Centralised env vars in orchestration layer
Ready to build
Sandbox testing
Zendesk sandbox, Notion test DB, HubSpot sandbox
Confirm access
Total confirmed build effort is 38 hours across a 4-week delivery window. The FullSpec team manages every stage of build, testing, and handover. For any questions about this specification, credential requirements, or pre-build readiness, contact the FullSpec team at support@gofullspec.com.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for FAQ & First Response Automation.

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