Build a two-way SMS support line from scratch
A two-way SMS support line is a number customers can text and get a correct answer back — instantly for the questions a keyword can answer, and through a human or an automation for everything else. The pieces exist as separate guides (keyword rules, flow builder, inbound routing, tickets); this page is the assembly. You end with a working reply loop: inbound arrives → keyword decides → acknowledged in seconds, or escalated to a flow, or handed to a person — and every exchange stays in the conversation thread. You will:- Understand the two layers
- Define the keyword grammar
- Build the START path as a flow
- Wire escalation to a human agent
- Read inbound replies via webhook
- Run the complete order-status example
- Hold the compliance guard
1. Architecture in two layers
The line works because two layers split the traffic, each solving a different latency question:- Layer one — keyword rules answer in seconds with zero agent time.
HOURS,LOCATION,STATUS ORDER-1234,HELP— a reply the moment the keyword matches, no queue, no staff. Rules live under Settings → Auto-Reply Rules; the full reference is Auto-Reply Rules. - Layer two — flows and the Inbox handle what a keyword cannot. Structured sequences (collect an order number, check an opt-in, confirm a status) run as flows built in the Flow Builder; unstructured conversation lands in the Inbox where a teammate continues the same thread.
- Built-in consent handling.
STOP/START(and multilingual equivalents) are processed before anything else; keyword rules never see them. - Keyword rules, in creation order. Oldest matching rule wins; one message fires at most one rule.
- No match → the Inbox. The message opens or continues a conversation for a human, unless you add a catch-all rule or a routing rule that sends it somewhere more specific.
2. Define the keyword grammar
Pick the vocabulary before you create a single rule — one intent per keyword, specific rules created before broad ones (evaluation is oldest-first, so creation order is precedence). A grammatically complete support line needs four families:
Two consequences to plan for. First, HELP is your keyword — the consent trio has built-in handling, but a
HELP reply with support contact details and opt-out instructions is a tenant-owned message you author, on every channel you run. Second, triage words separate fast from slow: STATUS should trigger the order-status flow (section 6) rather than reply statically, because the answer depends on the order; SUPPORT and HUMAN can open a conversation and route it to a team. The match types, response-text rules, and management API are covered in Auto-Reply Rules; recyclable keyword patterns are collected in Keyword rules recipes.
3. The START path as a flow
START itself never reaches a flow — built-in consent handling records the re-opt-in first. What you build as a flow is the welcome-back experience the re-opted-in contact should receive: confirm they can receive messages again, restate what your line does, and point at the menu. The consent flip is the platform’s; the acknowledgement copy and any conditional logic are yours, and a flow is the right home for that because you get condition nodes, opt-in checks, and branch paths for free.
Open Flows → Create New Flow (the full node reference is the Flow Builder) and lay out three nodes:
- Trigger — Contact Action
opted_in, Activation Conditionchannel = sms. The flow starts when a contact re-consents on SMS. - Condition — check the opt-in status you care about. Branch on
contact.opt_in_status = opted_infor the SMS channel so a partial or different-channel opt-in does not receive the “you’re resubscribed” text by mistake. - Send SMS — the confirmation. Something like:
You're re-subscribed to <brand> alerts. Text HELP for help, STATUS <order#> for an order, or STOP to opt out.
STOP, confirm the outbound side goes quiet, text START, and expect the flow’s send within seconds — the run appears in the flow’s execution history with the trigger event attached. Where the consent record itself lives (per-channel suppression and re-admission) is documented in Opt-out & opt-in rules.
4. Escalation to a human agent
A keyword that a flow cannot finish, or a message with no keyword at all, ends with a person. Two surfaces, chosen by the shape of the work:- Long-lived tracked work → Tickets. “Refund request,” “order arrived damaged” — a ticket carries a subject, priority, assignee, and SLA across days and agents. Create tickets from a flow (
HTTP Requestnode against the tickets endpoint) or let operators open them from a conversation; the queue mechanics are in Inbox Tickets workflow. - Live threaded conversation → the Inbox. The unmatched branch of your keyword tree lands here by default. Add structure on top: a routing rule that assigns inbound SMS to a named team, or a catch-all keyword rule that forwards to a deployed AI agent before it ever waits on a human. Both patterns — with the exact catch-all JSON and the routing-rule precedence — are in Keyword auto-replies with agent escalation, end to end.
HUMAN with action: "trigger_flow" into a flow that opens a ticket and notifies the on-call channel, or a forward_agent action for the AI-agent-first variant. The rule still fires in layer one, so the acknowledgment is instant; the expensive part runs asynchronously in the flow.
5. Read inbound replies via webhook
The Inbox shows inbound replies to your team, but your own systems often need the same stream — to log threads in a CRM, trigger provisioning, or measure response latency. Two webhook surfaces cover it:- Delivery receipts (
message.sent,message.delivered,message.read,message.failed) tell you what happened to outbound messages — the auto-replies and flow sends your line produces. Build a DLR-only webhook consumer is the minimal receiver for exactly those four events, with HMAC verification, dedupe on the event id, and thedata.statusfailure branch. - Inbound message events deliver the reply side. The per-channel event list (SMS
message.received, WhatsApp, RCS, Viber, and the voicecall.*family) is in Wire delivery-report webhooks per channel; subscribe the same endpoint pattern the DLR consumer uses and branch ondata.channel.
message.failed with rejected on the auto-reply side is a list-hygiene signal, not an agent signal). If you would rather route inbound SMS to your own endpoint before the keyword layer, that is the pre-inbox inbound SMS routing engine — rules with number / sender / keyword / regex match conditions targeting a webhook, ordered by priority. Keyword rules still run after routed webhooks ack; use routing only when your endpoint must see the message before the line does.
6. Worked example: order status
The complete loop for the most common support keyword — an order-status line whereSTATUS <order#> returns live order data, HELP explains the menu, SUPPORT opens a tracked ticket, and everything else falls to the team. Run it top to bottom against a reply-capable number.
Step 1 — create the status lookup flow
A flow that takes the inbound text, extracts the order number, calls your order API, and replies:GET /api/v1/flows/<id>/validate, then deploy. Keep the flow’s output variable naming (lookup_order) readable; the reply body references it as a {{…}} placeholder.
Step 2 — register the keyword rules, specific before broad
Match type: starts_with lets STATUS ORDER-1234 fire the flow with the full body as its trigger context. Create STATUS and HELP before any fallback — if you add one — because the oldest matching rule wins.
The same tree as the rules JSON for a seed script or an environment clone (verbatim request bodies, created in this order):
Step 3 — route the support branch to a team
TheSUPPORT keyword acknowledges instantly; route the actual SMS channel to the support team so every thread that keyword opens has an owner:
Step 4 — subscribe for receipts and inbound events
whsec_… signing secret from the response immediately; it is shown once.
Step 5 — prove the loop from a handset
- Text
STATUS ORDER-1234— expect the flow’s reply in seconds, and a run in the flow’s execution history. - Text
HELP— expect the menu reply. - Text
SUPPORT— expect the acknowledgement and a conversation assigned toteam_supportin the Inbox. - Text free-form (“where is my refund?”) — expect no keyword reply, and the message waiting in the same team’s queue.
- Read back both directions to confirm the loop recorded cleanly:
7. Compliance guard
The line you just built touches consent at three points; each is a tenant-owned control, and the ordering is the guard.- STOP/START run before everything. Built-in consent handling processes the opt-out/opt-in vocabulary before keyword rules, routing rules, and flows. Consequences you design around: never create a custom
STOPkeyword rule (it can never fire); never treat a keyword reply as a channel for a suppressed contact — an outbound Auto-Reply to an opted-out contact fails at send time, which is correct, and the send failure appears on the delivery side. - HELP goes out on ask, not on a schedule. Your
HELPreply copy — support contact plus opt-out instructions — is yours to author and keep accurate per channel. Add brand-specific aliases (QUIT,UNSUB) on the Opt-out & opt-in rules page when your audience uses them; they write to the same consent record the built-in words use. - Preserve the thread through handoffs. A keyword-triggered reply, a flow send, and a human reply all stay on one conversation as long as you reply from the same number the customer texted. Swapping senders mid-thread splits the conversation on the customer’s handset and strands the history the next agent needs. During escalation — ticket opened, team assigned, agent forwarded — the inbound keyword and its auto-reply are ordinary messages on that thread, so the human who picks it up starts with the full context instead of a cold ticket.
- Quiet hours apply to what your line initiates. Keyword replies answer an inbound, but a flow or agent that initiates outreach travels the marketing pipeline — gate it per channel in Quiet hours before traffic arrives.
See also
- Auto-Reply Rules — match types, precedence ordering, and the rules API
- Keyword rules recipes — match-type expectations across common patterns
- Keyword auto-replies with agent escalation — catch-all rules, agent forwards, routing into teams, SLA clocks
- Flow Builder — every node type and the definition format the flows API accepts
- Inbound SMS routing — pre-inbox rules that target webhooks, queues, and inboxes
- Two-way SMS conversations — the thread map beneath the Inbox
- Inbox Tickets workflow — assignments, SLA, and status audit for tracked work
- Build a DLR-only webhook consumer — minimal receiver for delivery events
- Wire DLR webhooks per channel — event families per channel, including inbound
- Opt-out & opt-in rules — built-in consent plus brand-owned vocabulary
- Quiet hours — the per-channel gate for initiated outreach