A ticket router on AWS for a few dollars a month
A small support team gets more tickets than anyone can sort by hand. The billing question that should go to finance, not the help desk. The angry email from a customer whose site is down, sitting behind forty routine how-do-I questions. The feature request that nobody on support can answer. The same customer who emails, fills in the web form, and pings chat about the same problem. Sorting all of that — reading each one, deciding what it’s about, judging how urgent it is, and getting it to the right person — eats the morning before a single reply goes out. This post walks through the design of a small router that reads each new ticket, tags it, and sends it to the right team — and flags anything angry or urgent so it jumps the queue. It never answers the customer itself; a person always does that.
Key takeaways
- Three sources for tickets: an email inbox, a web form on your site, and a chat lane — all land as one ticket.
- Every ticket ends in one of four moves: route, priority, escalate, or hold for a human to look at.
- One small model call per ticket reads the topic, the urgency, and the tone. Nothing else uses a model.
- The router only sorts and routes. It never writes a reply to the customer. A person always answers.
- Designed on AWS for about $3/month at typical small-business volume.
The whole system on one page
Before any code, here’s the shape of what we’re designing.
What you set up once (the outside)
- Incoming tickets. Three ways a ticket can arrive, all covered in Part 2 — an email inbox (forward your support address into a dedicated one and every email becomes a ticket), a web form on your site (the “Contact support” form posts straight to a small endpoint), and a chat lane (your chat tool drops finished conversations in as tickets). Whichever way it comes in, it ends up as one ticket with the customer, the subject, and the message body.
- A rules folder. One Google Sheet and one short Google Doc in a Drive folder. The sheet maps each topic to a team or person — “billing → finance, login problems → support, feature requests → product.” The doc covers the words that mean urgent (outage, down, refund, deadline), the VIP customer list (whose tickets always jump the queue), and the priority rules. The doc also holds a handful of labelled examples — a few real tickets with the right topic next to each — that help the router pick well.
- Teams. The people who actually answer. Each team has a Slack channel (so the ticket lands where the team already works) or, if Slack isn’t set up for them, a shared inbox. Tickets land with the customer name, the topic, the urgency, the tone, the original message, and a one-click “Reassign” button if the router got it wrong.
What runs on every ticket (the inside)
- The ticket intake. Three sources feed one queue. Each new ticket is written once, given an id, and checked against the last few tickets from the same customer so three copies of the same problem become one. Then a single Bedrock Haiku 4.5 call reads the ticket and returns three things: the topic (which bucket it belongs in), the urgency (how soon someone has to act), and the tone (is the customer calm, confused, or angry). The model reads; it does not reply.
- The router. Takes the topic, urgency, and tone and turns them into a move. It reads the rules sheet to find the team for that topic, checks the VIP list and the priority rules in the doc, and picks one of four moves. Route: normal ticket — send it to the right team’s normal queue. Priority: urgent or from a VIP — send it to the same team but put it at the top and ping the lead. Escalate: angry and urgent, or a VIP outage — flag it loudly so a manager sees it right away. Hold: the topic is unclear or the ticket is half-empty — drop it in a small triage lane for a human to sort, rather than guess. The move logic is plain Python; the only model call already happened on intake.
- The hand-off. Sends the tagged ticket to the team the router chose. Slack messages go to the team channel; email goes through SES outbound to a shared inbox. Priority and escalate tickets go to the top of the list and ping the lead. Every hand-off writes a row in DynamoDB so you can see where each ticket went and how long it waited. A weekly digest shows volume by topic and how often the router was corrected; a monthly summary writes a short paragraph: busiest topics, slowest queues, and the corrections that taught the router something.
In plain words
A customer emails at 8:54am: “Our store has been down for an hour, we’re losing sales, please help NOW.” The intake writes the ticket and reads it: topic is outage, urgency is high, tone is angry. The customer is on the VIP list. The router picks escalate: the ticket lands at the top of the engineering channel and pings the on-call lead in Slack, with the full message attached. Meanwhile a second customer asks “how do I change my billing address?” — topic billing, urgency low, tone calm — and that one routes quietly to the finance queue. Nobody had to read either ticket to sort it. And in both cases, a person writes the actual reply; the router never speaks to the customer.
The cost of running this is about $3 a month at SMB volume. The cost of not running it is the outage email that sat unread behind forty routine questions, the billing query that bounced between three people before reaching finance, and the angry customer who waited because nobody spotted that they were angry.
Design rules that shaped every decision
- The router sorts and routes; it never answers the customer. The reply stays fully in human hands.
- Four moves, always. Route, priority, escalate, hold. There is no fifth.
- When the topic is unclear, the router holds for a human instead of guessing. A wrong route is worse than a held one.
- Angry, urgent, and VIP tickets jump the queue. The team sees them first, with full context.
- The rules live in Drive. Adding a topic, changing a team, or tuning the urgency words doesn’t need a deploy.
- Every route and every correction is logged. A misroute is one click to fix, and the router learns from it.
Why this shape
Most teams sort tickets one of three ways: a shared inbox where whoever’s free grabs the next one, a single “support” queue that a person triages by hand each morning, or a pile of rules in the help-desk tool that nobody maintains. The shared inbox works until it’s busy — and the busiest mornings are exactly when the urgent ticket gets buried. The hand-triage works until the person doing it is out. And the rules-in-the-tool approach breaks the first time a customer phrases something in a way the keyword rule didn’t expect.
The setup above keeps the rules in a sheet the team already edits, but adds a small system that reads each ticket the way a person would — getting the gist, not just matching keywords — and acts on it the same second it arrives. Urgent tickets surface immediately. Unclear ones go to a human instead of the wrong team. And every correction makes the next sort a little better. The router is invisible on the easy tickets; it earns its place on the messy ones and the urgent ones.
The next four posts walk through each piece in turn: how a ticket gets read, how a ticket gets routed, how a ticket reaches the right team, and how a misroute gets corrected. One diagram per post. A cost breakdown and a final engineering reference at the end.
All posts