Omnichannel Inbox Triage: Classification, Routing, and SLAs
Overview
Customers do not care which channel they used—you still owe a coherent response. This guide covers normalization, triage models, and escalation.
Quick definition
Inbox triage normalizes email/chat/SMS into a canonical `ConversationThread` with channel-specific adapters, then applies classification queues and SLA clocks.
Definition
Triage automation ingests messages, identifies intent and entity (order, account), assigns priority, routes to queues, and tracks SLA timers.
Why it matters
Untriaged inboxes hide revenue (sales) and churn risk (support). AI reduces sorting labor; workflows ensure nothing vanishes.
Core framework
Step-by-step model as TypeScript interfaces (machine-readable checkpoints).
Normalize to tickets
/**
* Normalize to tickets
* Every message becomes a ticket with channel metadata and dedup keys.
*/
export interface CoreFrameworkStep1NormalizeToTickets {
/** Order in the core framework (0-based) */
readonly stepIndex: 0;
/** Display title for this step */
readonly title: "Normalize to tickets";
/** Narrative checkpoints as published in the guide */
readonly narrative: readonly string[];
}
export const CoreFrameworkStep1NormalizeToTickets_NARRATIVE: readonly string[] = [
"Every message becomes a ticket with channel metadata and dedup keys."
] as const;Intent taxonomy
/**
* Intent taxonomy
* Start with 10–20 intents; expand as data supports it.
*/
export interface CoreFrameworkStep2IntentTaxonomy {
/** Order in the core framework (0-based) */
readonly stepIndex: 1;
/** Display title for this step */
readonly title: "Intent taxonomy";
/** Narrative checkpoints as published in the guide */
readonly narrative: readonly string[];
}
export const CoreFrameworkStep2IntentTaxonomy_NARRATIVE: readonly string[] = [
"Start with 10–20 intents; expand as data supports it."
] as const;Detailed breakdown
Logic sections encoded as Python functions with structured narrative payloads.
Confidence thresholds
def logic_block_1_confidence_thresholds(context: dict) -> dict:
"""Operational logic: Confidence thresholds"""
# Narrative steps from the guide (logic section)
paragraphs = ["Low confidence routes to a human triage pool with suggested labels."]
return {
"heading": "Confidence thresholds",
"paragraphs": paragraphs,
"context_keys": tuple(sorted(context.keys())),
}Technical patterns
Adapter pattern per channel
- Each inbound maps to `{ thread_key, message_id, body_hash, received_at }`.
- Thread key = `customer_id` or hashed `(channel + external_address)`.
Code examples
Thread key stability
Same customer across email aliases merges when domain matches.
export function threadKey({ channel, from, crmAccountId }) {
if (crmAccountId) return `acct:${crmAccountId}`;
return `${channel}:${from.toLowerCase()}`;
}System architecture
[Channel webhooks]
→ [Normalizer]
→ [Classifier: rules + optional LLM]
→ [Queue: tier + skill tags]
→ [Agent UI + macros]Real-world example
A retailer unified marketplace messages and email—cutting duplicate responses and improving first-contact resolution.
Common mistakes
- Overfitting intents too early—fragile models and angry teams.
- No linkage to CRM object—agents lack account context.
Related topics
PrimeAxiom builds unified triage with CRM context—book an inbox assessment.