Voice AI

Build an SMS Support Agent That Actually Follows Up

Most support bots can answer a message.

That is useful, but it is not quite the same thing as support.

Real support has memory. It knows what the customer asked. It knows what answer was sent. It knows whether the conversation is still unresolved. And if a customer goes quiet after getting help, a good support workflow can check back in without someone manually setting a reminder.

That is the pattern this example demonstrates.

sms-support-agent-with-followup is a TypeScript example that runs on Telnyx Edge Compute with the Telnyx Agent SDK. It receives inbound SMS messages, answers with Telnyx AI Inference, sends the reply through Telnyx Messaging, stores the conversation per phone number, and schedules a follow-up check-in 24 hours later.

Code: https://github.com/team-telnyx/telnyx-code-examples/tree/main/sms-support-agent-with-followup

What we are building

The app is an SMS support agent.

A customer texts a Telnyx number with a support question. Telnyx sends a message.received webhook to the Edge Compute function. The function routes that message to a SupportAgent actor instance keyed by the sender's phone number.

From there, the agent owns the support turn:

Inbound SMS
  -> Edge Compute webhook
  -> SupportAgent.receive()
  -> durable message history
  -> queued AI turn
  -> Telnyx AI Inference
  -> outbound SMS reply
  -> scheduled 24h follow-up

The customer experiences this as a normal SMS conversation. The developer gets a durable agent behind the scenes.

Why the Agent SDK matters here

The interesting part is not that the app calls an LLM. A lot of examples do that.

The interesting part is that the support workflow has lifecycle primitives built in.

The SupportAgent extends the Agent SDK Agent class. That gives the app:

  • durable message history with this.messages.add()
  • OpenAI-shaped conversation export with this.messages.toOpenAI()
  • queued background work with this.queue()
  • scheduled follow-up work with this.schedule()
  • per-conversation state with this.setState() and this.getState()
  • zero-credential access to Telnyx APIs through this.env.TELNYX

That combination is what turns a simple webhook into an agent-shaped application.

The webhook does not need to hold the request open while the model runs. It records the incoming message, queues the processing step, and returns quickly. The AI turn runs in the background, then sends the SMS response.

For messaging apps, that shape matters. Webhooks should acknowledge quickly. Long-running model calls should not make webhook delivery fragile.

No API key in the application code

The sample uses the [telnyx] binding in telnyx.toml:

[telnyx]
binding = "TELNYX"

Inside the agent, that exposes a pre-authenticated Telnyx client:

await this.env.TELNYX.ai.openai.chat.createCompletion(...)
await this.env.TELNYX.messages.send(...)

So the same Edge Compute function can call Telnyx AI Inference and Telnyx Messaging without hardcoding an API key into the app.

That is a small detail with a big operational payoff. The agent code focuses on the support workflow, while credentials stay in the platform binding.

The support turn

When an SMS comes in, the front-door handler extracts the sender, recipient, and message text from the Telnyx webhook payload.

Then it routes the message to a per-phone-number actor:

await env.SUPPORT.idFromName(actorName(from)).receive({
  text,
  from,
  to,
});

Inside receive(), the agent stores the message and queues the AI turn:

await this.setState({ from, to });
await this.messages.add("user", text);
await this.queue("process");

The process() method reads the conversation history, calls Telnyx AI Inference, stores the assistant reply, sends the SMS, and schedules a follow-up:

const history = await this.messages.toOpenAI();

const completion = await this.env.TELNYX.ai.openai.chat.createCompletion({
  model: "zai-org/GLM-5.2",
  messages: [{ role: "system", content: SYSTEM_PROMPT }, ...history],
  max_tokens: 1000,
  temperature: 0.7,
});

After the reply is sent, the agent schedules:

await this.schedule(86400, "followup", null, {
  id: `followup-${state.from}`,
});

That creates the 24-hour check-in.

The follow-up

The follow-up behavior is intentionally simple.

When the scheduled task fires, the agent checks the last message in the conversation. If the last message is still from the assistant, that means the customer has not replied since the support answer.

In that case, the agent sends:

Did that solve your problem? Reply yes or no, or ask for a human.

If the customer already replied, the follow-up is skipped.

This is a tiny pattern, but it is useful. A lot of support workflows are not one message long. The actual experience is closer to:

  • customer asks a question
  • agent answers
  • customer gets busy
  • workflow checks back later
  • unresolved issues can be escalated

The Agent SDK gives you the primitives to model that lifecycle without adding a separate worker queue, scheduler, conversation database, and messaging integration just to get the first version working.

Testing it

The app includes a debug route so you can simulate an inbound SMS before wiring up a real messaging profile:

curl -X POST https://sms-support-agent-<id>.telnyxcompute.com/debug/message \
  -H "Content-Type: application/json" \
  -d '{
    "from":"+15551230000",
    "to":"+15559870000",
    "text":"How do I send an SMS?"
  }'

The response confirms the message was queued:

{
  "action": "queued",
  "from": "+15551230000",
  "to": "+15559870000"
}

For real SMS, point your Telnyx Messaging Profile webhook to:

https://sms-support-agent-<id>.telnyxcompute.com/webhooks/sms

Then text the Telnyx number.

Where this pattern goes next

This sample is intentionally small, but the architecture is production-shaped.

The same pattern can grow into:

  • customer support triage
  • order status agents
  • appointment reminders
  • billing support
  • onboarding assistants
  • renewal check-ins
  • human handoff workflows

Before using it in production, I would add webhook signature verification, opt-out handling, idempotent outbound sends, rate limits, human escalation rules, and clear retention policies for message history.

But the core idea is already here.

Your support agent should not just answer.

It should remember, continue work in the background, and know when to check back.

Resources

  • Code: https://github.com/team-telnyx/telnyx-code-examples/tree/main/sms-support-agent-with-followup
  • Agent SDK docs: https://developers.telnyx.com/docs/agent-sdk
  • Agent SDK quickstart: https://developers.telnyx.com/docs/agent-sdk/quickstart
  • Roll Your Own Agent: https://developers.telnyx.com/docs/agent-sdk/examples/roll-your-own
  • Edge Compute docs: https://developers.telnyx.com/docs/edge-compute
  • Messaging docs: https://developers.telnyx.com/docs/messaging
  • Telnyx AI Inference docs: https://developers.telnyx.com/docs/inference
  • Telnyx AI skills and toolkits: https://github.com/team-telnyx/ai
  • Telnyx Portal: https://portal.telnyx.com/

Ready to build with low-latency voice AI?

Join developers building the future of real-time conversations