Part 4 of 7 · Ticket router series ~5 min read

How a ticket reaches the right team

The router picked a move — route, priority, or escalate. Now the hand-off has to figure out which channel, at what queue position, with what context attached, and without pinging the same team twice for one problem. Get any of those wrong and the hand-off is worse than none: an urgent ticket buried in a normal queue, a duplicate that fires three Slack pings, a hand-off with no detail that makes someone open four tabs to understand it. Four small guardrails sit between the move and the ticket landing.

Key takeaways

  • Team resolution: per-customer override beats per-topic default beats fallback to the general triage lane.
  • Slack channels are the default; a shared inbox via email is the fallback if no channel is set.
  • Priority and escalate tickets jump the queue and ping the lead or a manager.
  • Every hand-off ships with the customer, topic, urgency, tone, the original message, and a Reassign button.
  • A duplicate check stops the same problem from pinging a team more than once.

Four guardrails on every hand-off

Four guardrails between the router's chosen move and the landed ticket A horizontal flow diagram. On the far left, a "Move chosen" box: the router picked the ticket's team and one of three sending moves — route, priority, or escalate. Four guardrail gates sit in a row to the right, each drawn as a vertical bar. Gate 1: Resolve team — looks up the per-customer override first; if none, falls back to the per-topic team from the rules sheet; if still none, falls back to the general triage lane. Returns a Slack channel if one is set, otherwise a shared inbox email address. Gate 2: Queue position — a route move goes to the bottom of the team's normal queue; a priority move goes to the top and pings the team lead; an escalate move goes to the top and pings a manager directly. Gate 3: Duplicate check — looks at recent tickets from the same customer about the same topic; if this is a repeat of one already handed off, it attaches to that ticket instead of firing a second ping. Gate 4: Compose plus context — formats the hand-off message: customer, topic, urgency, tone, the original message, and a Reassign button. After all four gates pass, the ticket ships via the Slack chat.postMessage API for the resolved channel, or via SES outbound for the resolved inbox. A note at the bottom: every hand-off is logged to DynamoDB so the queue and the corrections both have a record. Move chosen route, priority, or escalate Gate 1 Resolve team customer pin? topic default? triage fallback? prefer Slack, fall back to inbox Gate 2 Queue position route → bottom of the queue priority/escalate → top, ping lead or manager Gate 3 Duplicate check same customer, same topic? if yes, attach to the open ticket, no ping Gate 4 Compose + context hand-off card for the team + topic, urgency, tone, message, Reassign button Hand-off — Slack channel (preferred) or SES outbound inbox (fallback) chat.postMessage for Slack · SES SendRawEmail for inbox every hand-off logged to DDB tr-routes — the queue and corrections have a record Every gate is a deterministic check — no model calls, no surprise pings on a busy morning.
Fig 4. Four guardrails between the move and the landed ticket. Resolve the team. Set the queue position. Skip duplicates. Compose with full context. Then ship via Slack or email and log the hand-off so the queue and the corrections both have a record.

Gate 1: resolve the team

Three places the hand-off looks for the team, in order. First, the per-customer override in the VIP list — if a row pins a named customer to a named person, that wins regardless of topic. Second, the per-topic team from the rules sheet (“billing goes to finance”). Third, the general triage lane — the catch-all that a human watches. The triage fallback should rarely fire in steady state; if it does, the weekly digest names every ticket that hit it so the rules sheet can be filled in.

Once the hand-off knows which team, it looks up where the team works. The rules sheet maps each team to a Slack channel if one is set, otherwise to a shared inbox email. Slack is preferred because the team already lives there and a Slack card with a Reassign button is more useful than a forwarded email. Email is the fallback so a team without Slack still gets its tickets.

Gate 2: queue position

The move decides where the ticket lands in the team’s list. A route move drops the ticket at the bottom of the normal queue — it shows up, quietly, in turn. A priority move puts it at the top and pings the team lead, so the team sees it before the routine pile. An escalate move also goes to the top, but pings a manager directly, because escalate is the small set of tickets where a minute matters.

The pings are deliberate and rare. A team that gets pinged for every ticket learns to ignore the pings; a team that gets pinged only for priority and escalate learns that a ping means “look now.” Keeping route silent is what makes the priority ping mean something.

Gate 3: duplicate check

Customers repeat themselves. The same person emails, then fills in the form, then pings chat about one outage. Without a guard, that’s three tickets and three pings for one problem. Gate 3 looks at recent tickets from the same customer about the same topic; if this ticket is a repeat of one already handed off and still open, it attaches the new message to that ticket instead of firing a second ping. The team sees “customer followed up” on the existing card, not a fresh duplicate.

The check is conservative on purpose. It only merges when the customer and the topic both match a still-open ticket within a short window. A genuinely new problem from the same customer — different topic, or a ticket already closed — starts its own card. Merging too aggressively would hide real tickets; merging carefully just removes the obvious echoes.

Gate 4: compose with full context, then ship

The hand-off card carries everything the team needs to start without asking a follow-up question: the customer name, the topic the router picked, the urgency, the tone, the original message in full, and the source it came from. It also carries a Reassign button — one tap to move the ticket to a different team if the router got it wrong. For Slack, the card is posted via the chat API with the button as a Block Kit action. For the email fallback, the same fields are wrapped in a short HTML email, and the Reassign button is a link to a Function URL that records the change.

An escalate move adds a line the others don’t: why it escalated — “angry tone, outage mentioned, VIP customer” — so the manager sees the reason at a glance instead of having to reread the whole ticket to judge it.

Every hand-off — Slack or email, route or escalate — writes a row to tr-routes in DynamoDB. That row is what the queue reads and what a correction later updates.

Why the guardrails exist

None of these gates are clever. They’re the small care a thoughtful person would take if they were handing tickets to teams by hand — check who actually owns this, put the urgent ones on top, don’t hand the same thing over twice, include enough context that the team can start straight away. Putting them in code as four small sequential gates makes them part of the design, not something you’re trusting a busy morning to remember.

Next post: how a misroute gets corrected — the Reassign button, the priority bump, the split, and how each correction teaches the router to do better next time.

All posts