Support ticket triage agent
One n8n workflow that classifies, routes and drafts support tickets, and never answers on its own
Eight cases you can trigger yourself
The demo posts to the same webhook as the source repository, with the same workflow, the same policy rows and the same provider. Every scenario states what it expects before it runs, then shows the actual result and the PostgreSQL rows behind it. Classification is probabilistic and is labelled as such; the policy checks are not. If the live provider fails during your run, the console says so and shows the safe degradation instead of a result.
It stops instead of guessing
Urgent, sensitive, low-confidence and incomplete tickets go to a human with no draft.
VERIFY: Run Ambiguous request and Sensitive topicRouting is deterministic
The same urgent ticket routes to human review inside business hours and to on-call outside them.
VERIFY: Run Urgent during business hours, then After-hours urgentDuplicates cost nothing
A repeated event returns the stored result, with one ticket and one decision in the database.
VERIFY: Run Duplicate eventFailures are loud and safe
A permanent provider failure returns HTTP 503, keeps the ticket for review and opens an alert.
VERIFY: Run Permanent provider failureRetries are bounded and recorded
A transient provider error is retried with backoff and written to the audit trail as retry_scheduled.
VERIFY: Run Transient provider errorEvery decision is auditable
Ticket, decision, cited sources, audit actions and alerts are read back from PostgreSQL after each run.
VERIFY: Open the PostgreSQL evidence panel under any result- Public console validates a synthetic ticket and posts it to the internal n8n webhook
- The workflow checks the intake contract and rejects an invalid one with HTTP 400
- PostgreSQL reserves the external ticket ID atomically before any provider call
- One provider classifies into a strict JSON schema with bounded retries
- SQL policy applies sensitive topics, required fields, confidence, timezone and business hours
- A grounded draft is created only when exactly one active knowledge version matches
- Decision, cited sources and audit actions are written in one transaction
- A separate error workflow records failures and raises an operational alert
Synthetic customers and tickets only. n8n, PostgreSQL and the provider key stay on the internal Docker network; the console is the single public surface.
- Only the ticket subject and message reach the model provider. Customer records, policy rows and knowledge articles stay in PostgreSQL.
- The browser never receives the webhook URL, the database URL or the provider key.
- Provider processing region and retention are not configured or measured for this reference implementation.
- Operational alerts stay in PostgreSQL. No external notification channel is configured.
- The demo database resets to its seeded state every night at 04:00 CET.
Support inboxes fail in the same two ways. Either everything waits for a person, or an assistant answers confidently and gets it wrong. This build takes the second risk seriously: the model is allowed to read and classify, and nothing else.
A ticket arrives on an n8n webhook and is validated against a strict intake contract. PostgreSQL reserves the external ticket ID atomically, so a repeated event returns the stored result instead of paying for a second classification. One provider then classifies the ticket into a fixed JSON schema. Output that does not fit the schema is treated as a provider failure, not as a guess.
Everything after that is deterministic. Sensitive topics are matched by phrase in SQL. Required fields depend on the category. Confidence below the 0.75 policy row forces human review. Queue, timezone and business hours come from rule tables, so the same urgent ticket routes to human review inside office hours and to on-call outside them. A grounded draft is written only when exactly one active knowledge version matches, and it is never sent.
This is a spec project built on a public brief, with synthetic customers and tickets. The measured test report is included rather than summarised: five consecutive runs of a 42-scenario catalog passed 202 of 210 executions, and all eight failures were live classification drift that still ended in human review or a safe error.
What it does
- Structured classification with category, priority, confidence and reason codes against a strict schema
- Routing, business hours, timezone and escalation rules stored as PostgreSQL rows, not in the prompt
- Grounded drafts from exactly one active knowledge version, never sent automatically
- Atomic idempotency in PostgreSQL before the provider is called, verified under concurrent duplicates
- Bounded retries, a separate error workflow and operational alerts on provider failure
- Append-only audit trail per ticket and a versioned catalog of 42 automated scenarios




Want something like this for your business?