Skip to main content

Sample Flow: AI Support Bot

An AI-powered support ticket workflow that classifies issues and routes them to the appropriate team with an automated response.


Overview

What it does:

  1. Receives an incoming support request (customer name, email, message)
  2. Uses an AI Task to classify the issue and generate an initial response
  3. Routes to the correct team (billing, technical, or general support) based on classification
  4. Sends a confirmation email to the customer with the AI-generated response
  5. Logs the ticket to the database

Execution time: 5–15 seconds (depends on LLM response speed)


Prerequisites

Before importing this workflow, set up:

RequirementTypeWhere to Create
OpenAI GPT-4oAI Provider IntegrationConnections → Add Connection
Company email providerEmail IntegrationConnections → Add Connection
Tickets databaseDatabase IntegrationConnections → Add Connection
OPENAI_API_KEYSecretSecrets → Add Secret

Update the placeholder IDs in the workflow after import:

  • int_openai_placeholder → your AI provider integration ID
  • int_email_placeholder → your email integration ID
  • int_db_placeholder → your database integration ID

Input Variables

Trigger this workflow with:

{
"processId": "proc_ai_support_bot",
"data": {
"customerName": "Jane Smith",
"customerEmail": "jane@example.com",
"ticketMessage": "I was charged twice for my subscription this month. Please help.",
"ticketId": "TKT-5521"
}
}
VariableRequiredDescription
customerNameYesCustomer's full name
customerEmailYesCustomer's email address
ticketMessageYesThe support request text
ticketIdYesUnique ticket identifier

Workflow Steps

[Start Event]

[AI Task: Classify & Respond]
→ Classification: billing / technical / account / general
→ Priority: low / medium / high / critical
→ AI response draft

[Script Task: Validate Classification]
→ Ensures valid classification, sets defaults

[If/Else: Is billing?]
↓ trueFlow
[Email: Billing Team Alert]
↓ falseFlow
[If/Else: Is technical?]
↓ trueFlow
[Email: Technical Team Alert]
↓ falseFlow
[Email: General Support Alert]
↓ (all paths merge)
[SQL: Log Ticket to Database]

[Email: Customer Confirmation]

[Output Node: Completion]

[End Event]

Node Configuration Details

AI Task: Classify & Respond

aiProviderConnectionId: int_openai_placeholder
systemPrompt: You are a customer support classification expert for {companyName}.
Your job is to analyze support tickets, classify them, assess priority, and draft an empathetic response.
Always respond with valid JSON only.

prompt: Analyze this support ticket and respond with JSON:
Customer: {customerName}
Email: {customerEmail}
Message: {ticketMessage}

Respond with:
{
"classification": "billing|technical|account|general",
"priority": "low|medium|high|critical",
"needsHuman": true|false,
"estimatedResolutionHours": <number>,
"draftResponse": "<empathetic, helpful response to the customer>"
}

Output variables after this node: {classification}, {priority}, {needsHuman}, {estimatedResolutionHours}, {draftResponse}


Script Task: Validate Classification

const validClassifications = ['billing', 'technical', 'account', 'general'];
const validPriorities = ['low', 'medium', 'high', 'critical'];

const safeClassification = validClassifications.includes(classification)
? classification
: 'general';

const safePriority = validPriorities.includes(priority)
? priority
: 'medium';

return {
classification: safeClassification,
priority: safePriority,
teamEmail: safeClassification === 'billing'
? 'billing@yourcompany.com'
: safeClassification === 'technical'
? 'tech@yourcompany.com'
: 'support@yourcompany.com'
};

Email: Customer Confirmation

mailConnectionId: int_email_placeholder
recipientAddress: {customerEmail}
subject: RE: Your Support Request #{ticketId}
contentType: text/html
body:
<p>Dear {customerName},</p>

<p>Thank you for reaching out to us. We've received your support request and our {classification} team will look into this for you.</p>

<p><strong>Our initial response:</strong></p>
<blockquote>{draftResponse}</blockquote>

<p><strong>Priority:</strong> {priority}<br>
<strong>Estimated resolution:</strong> {estimatedResolutionHours} hours<br>
<strong>Ticket ID:</strong> {ticketId}</p>

<p>We'll follow up with you shortly.</p>
<p>Best regards,<br>Support Team</p>

SQL: Log Ticket

INSERT INTO support_tickets
(ticket_id, customer_email, customer_name, message, classification, priority, needs_human, draft_response, created_at)
VALUES
('{ticketId}', '{customerEmail}', '{customerName}', '{ticketMessage}',
'{classification}', '{priority}', {needsHuman}, '{draftResponse}', NOW())

Output

After completion, the process instance data contains:

{
"customerName": "Jane Smith",
"customerEmail": "jane@example.com",
"ticketMessage": "I was charged twice...",
"ticketId": "TKT-5521",
"classification": "billing",
"priority": "high",
"needsHuman": true,
"estimatedResolutionHours": 4,
"draftResponse": "Dear Jane, I understand how frustrating it must be...",
"teamEmail": "billing@yourcompany.com",
"emailSent": true
}

Full Workflow JSON

Import this JSON into apptor flow. Remember to replace placeholder IDs.

{
"nodes": [
{
"nodeId": "start-1",
"name": "Start",
"nodeType": "startEvent"
},
{
"nodeId": "ai-classify-1",
"name": "Classify and Draft Response",
"nodeType": "aiTask",
"properties": {
"aiProviderConnectionId": "int_openai_placeholder",
"systemPrompt": "You are a customer support classification expert. Always respond with valid JSON only.",
"prompt": "Analyze this support ticket:\nCustomer: {customerName}\nMessage: {ticketMessage}\n\nRespond with JSON:\n{\"classification\": \"billing|technical|account|general\", \"priority\": \"low|medium|high|critical\", \"needsHuman\": true, \"estimatedResolutionHours\": 4, \"draftResponse\": \"<helpful response>\"}"
},
"timeout": { "duration": 30, "durationUom": "SECONDS", "action": "FAIL" },
"retry": { "maxAttempts": 2, "delay": 5, "delayUom": "SECONDS" }
},
{
"nodeId": "script-validate-1",
"name": "Validate Classification",
"nodeType": "scriptTask",
"properties": {
"scriptFormat": "javascript",
"script": "const valid = ['billing','technical','account','general']; const c = valid.includes(classification) ? classification : 'general'; const teamMap = {billing:'billing@yourcompany.com', technical:'tech@yourcompany.com'}; return { classification: c, teamEmail: teamMap[c] || 'support@yourcompany.com' };"
}
},
{
"nodeId": "ifelse-billing-1",
"name": "Is Billing?",
"nodeType": "ifElse"
},
{
"nodeId": "ifelse-technical-1",
"name": "Is Technical?",
"nodeType": "ifElse"
},
{
"nodeId": "email-billing-team",
"name": "Alert Billing Team",
"nodeType": "serviceTask",
"properties": {
"mailConnectionId": "int_email_placeholder",
"recipientAddress": "billing@yourcompany.com",
"subject": "New BILLING Ticket #{ticketId} - Priority: {priority}",
"body": "New billing ticket from {customerName} ({customerEmail}):\n\n{ticketMessage}\n\nAI Draft Response:\n{draftResponse}"
}
},
{
"nodeId": "email-technical-team",
"name": "Alert Technical Team",
"nodeType": "serviceTask",
"properties": {
"mailConnectionId": "int_email_placeholder",
"recipientAddress": "tech@yourcompany.com",
"subject": "New TECHNICAL Ticket #{ticketId} - Priority: {priority}",
"body": "New technical ticket from {customerName} ({customerEmail}):\n\n{ticketMessage}\n\nAI Draft Response:\n{draftResponse}"
}
},
{
"nodeId": "email-general-team",
"name": "Alert General Support",
"nodeType": "serviceTask",
"properties": {
"mailConnectionId": "int_email_placeholder",
"recipientAddress": "support@yourcompany.com",
"subject": "New Ticket #{ticketId} - Priority: {priority}",
"body": "New support ticket from {customerName} ({customerEmail}):\n\n{ticketMessage}\n\nAI Draft Response:\n{draftResponse}"
}
},
{
"nodeId": "sql-log-ticket",
"name": "Log Ticket to Database",
"nodeType": "serviceTask",
"properties": {
"databaseConnectionId": "int_db_placeholder",
"mode": "direct",
"queries": ["INSERT INTO support_tickets (ticket_id, customer_email, customer_name, message, classification, priority, created_at) VALUES ('{ticketId}', '{customerEmail}', '{customerName}', '{ticketMessage}', '{classification}', '{priority}', NOW()) ON CONFLICT (ticket_id) DO NOTHING"]
}
},
{
"nodeId": "email-customer-1",
"name": "Send Customer Confirmation",
"nodeType": "serviceTask",
"properties": {
"mailConnectionId": "int_email_placeholder",
"recipientAddress": "{customerEmail}",
"subject": "RE: Your Support Request #{ticketId}",
"contentType": "text/html",
"body": "<p>Dear {customerName},</p><p>Thank you for reaching out. Our team will assist you shortly.</p><p><strong>Our response:</strong><br>{draftResponse}</p><p>Ticket ID: {ticketId}</p>"
}
},
{
"nodeId": "end-1",
"name": "End",
"nodeType": "endEvent"
}
],
"links": [
{ "linkId": "l1", "sourceId": "start-1", "targetId": "ai-classify-1", "type": "sequenceFlow" },
{ "linkId": "l2", "sourceId": "ai-classify-1", "targetId": "script-validate-1", "type": "sequenceFlow" },
{ "linkId": "l3", "sourceId": "script-validate-1", "targetId": "ifelse-billing-1", "type": "sequenceFlow" },
{ "linkId": "l4", "sourceId": "ifelse-billing-1", "targetId": "email-billing-team", "type": "trueFlow", "condition": { "expression": "${classification == 'billing'}", "language": "juel" } },
{ "linkId": "l5", "sourceId": "ifelse-billing-1", "targetId": "ifelse-technical-1", "type": "falseFlow", "condition": { "expression": "${classification != 'billing'}", "language": "juel" } },
{ "linkId": "l6", "sourceId": "ifelse-technical-1", "targetId": "email-technical-team", "type": "trueFlow", "condition": { "expression": "${classification == 'technical'}", "language": "juel" } },
{ "linkId": "l7", "sourceId": "ifelse-technical-1", "targetId": "email-general-team", "type": "falseFlow", "condition": { "expression": "${classification != 'technical'}", "language": "juel" } },
{ "linkId": "l8", "sourceId": "email-billing-team", "targetId": "sql-log-ticket", "type": "sequenceFlow" },
{ "linkId": "l9", "sourceId": "email-technical-team", "targetId": "sql-log-ticket", "type": "sequenceFlow" },
{ "linkId": "l10", "sourceId": "email-general-team", "targetId": "sql-log-ticket", "type": "sequenceFlow" },
{ "linkId": "l11", "sourceId": "sql-log-ticket", "targetId": "email-customer-1", "type": "sequenceFlow" },
{ "linkId": "l12", "sourceId": "email-customer-1", "targetId": "end-1", "type": "sequenceFlow" }
]
}

Build This Yourself

Follow these steps to recreate this workflow in the designer:

  1. Navigate to /flows → click New Flow → name it "AI Support Bot" → Create
  2. From the Action Browser, drag onto canvas in order:
    • Start Event
    • AI Task (name: "Classify and Draft Response")
    • Script Task (name: "Validate Classification")
    • If/Else (name: "Is Billing?")
    • If/Else (name: "Is Technical?") — connect from the falseFlow of the first If/Else
    • Service Task – Email × 3 (one per team: billing, technical, general)
    • Service Task – SQL (name: "Log Ticket to Database")
    • Service Task – Email (name: "Send Customer Confirmation")
    • End Event
  3. Connect nodes: Start → AI Task → Script Task → If/Else (Billing) → ...
    • If/Else (Billing) trueFlow → Email Billing Team
    • If/Else (Billing) falseFlow → If/Else (Technical)
    • If/Else (Technical) trueFlow → Email Technical Team
    • If/Else (Technical) falseFlow → Email General Support
    • All three email nodes → SQL Log → Customer Confirmation Email → End
  4. Configure the AI Task: select your AI Provider connection, paste the system prompt and user prompt from the Node Configuration section above
  5. Configure each If/Else condition (Properties Panel → Condition field):
    • Is Billing? → ${classification == 'billing'}
    • Is Technical? → ${classification == 'technical'}
  6. Configure each Email node with the subject and body templates from above, using {variableName} syntax
  7. Configure the SQL node with your database connection and the INSERT query
  8. Click SavePublish
  9. Test by clicking Run and entering sample input data (customerName, customerEmail, ticketMessage, ticketId)