AINode.jsAutomation
AI-Powered SMS Response Bot with Twilio
TT
TopicTrick Team
AI-Powered SMS Response Bot with Twilio
SMS is the most universally accessible communication channel — no app, no account, works on every phone. This tool builds an intelligent two-way SMS bot that reads incoming messages and responds with GPT-4o, maintaining conversation context per phone number.
This is Tool 16 of the Build 50 AI Automation Tools course.
What You'll Build
- Receive incoming SMS via Twilio webhook
- Generate intelligent GPT-4o responses
- Maintain conversation history per phone number
- Custom commands: HELP, STOP, RESET
Setup
bash
mkdir sms-bot && cd sms-bot
npm init -y
npm install express twilio openai dotenvbash
# .env
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your-auth-token
TWILIO_PHONE_NUMBER=+15551234567
OPENAI_API_KEY=sk-your-key-here
PORT=3000Get credentials from console.twilio.com.
SMS Bot Server
js
// src/server.js
import 'dotenv/config';
import express from 'express';
import twilio from 'twilio';
import OpenAI from 'openai';
const app = express();
app.use(express.urlencoded({ extended: false }));
const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const { MessagingResponse } = twilio.twiml;
// Conversation history per phone number
const conversations = new Map();
const SYSTEM_PROMPT = `You are a helpful AI assistant responding via SMS.
Rules:
- Keep responses under 160 characters when possible (one SMS)
- If more detail is needed, keep under 320 characters
- Be direct and helpful — no unnecessary pleasantries
- If asked for a list, use simple numbered format: 1) ... 2) ...
- Never use markdown formatting (no **bold**, no #headers)`;
async function generateReply(from, message) {
if (!conversations.has(from)) conversations.set(from, []);
const history = conversations.get(from);
history.push({ role: 'user', content: message });
const response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'system', content: SYSTEM_PROMPT },
...history.slice(-6), // Last 3 exchanges
],
temperature: 0.7,
max_tokens: 200,
});
const reply = response.choices[0].message.content.trim();
history.push({ role: 'assistant', content: reply });
// Keep history manageable
if (history.length > 20) history.splice(0, 2);
return reply;
}
// Twilio webhook — receives incoming SMS
app.post('/sms', async (req, res) => {
const { Body: message, From: from } = req.body;
const twiml = new MessagingResponse();
let reply;
if (!message?.trim()) {
reply = 'Hi! Send me a message and I\'ll help you.';
} else if (message.toUpperCase() === 'STOP') {
conversations.delete(from);
reply = 'You have been unsubscribed. Reply START to opt back in.';
} else if (message.toUpperCase() === 'RESET') {
conversations.delete(from);
reply = 'Conversation cleared. How can I help you?';
} else if (message.toUpperCase() === 'HELP') {
reply = 'Commands: RESET (clear history), STOP (unsubscribe). Ask me anything!';
} else {
try {
reply = await generateReply(from, message);
} catch (err) {
console.error(err);
reply = 'Sorry, I had trouble processing that. Please try again.';
}
}
twiml.message(reply);
res.type('text/xml').send(twiml.toString());
});
// Send outbound SMS
app.post('/send', async (req, res, next) => {
try {
const { to, message } = req.body;
if (!to || !message) return res.status(400).json({ error: 'to and message required' });
const msg = await client.messages.create({
body: message,
from: process.env.TWILIO_PHONE_NUMBER,
to,
});
res.json({ success: true, sid: msg.sid });
} catch (err) { next(err); }
});
app.get('/health', (_req, res) => res.json({ status: 'ok' }));
app.use((err, _req, res, _next) => res.status(500).json({ error: err.message }));
app.listen(process.env.PORT ?? 3000, () => console.log('SMS Bot running'));Connecting Twilio
- In the Twilio Console, go to Phone Numbers → Manage → Active Numbers
- Click your Twilio number
- Under Messaging, set A MESSAGE COMES IN webhook to:
https://your-ngrok-url.ngrok.io/sms - Method: HTTP POST
- Save
For development, use ngrok: ngrok http 3000
Testing
bash
# Send a test outbound SMS
curl -X POST http://localhost:3000/send \
-H "Content-Type: application/json" \
-d '{"to": "+15559876543", "message": "Hello from your AI SMS bot!"}'Then text your Twilio number from your phone:
text
You: What is the capital of France?
Bot: Paris is the capital of France, with a population of about 2.1 million in the city proper.
You: How far is it from London?
Bot: Paris is about 340 km (214 miles) from London. By Eurostar, it takes around 2.5 hours.Business Use Case: FAQ Bot
js
const FAQ_SYSTEM_PROMPT = `You are the customer support bot for Acme Coffee Roasters.
Business info:
- Hours: Mon-Fri 8am-6pm EST
- Shipping: Free over $50, otherwise $5.99
- Subscriptions: Weekly, bi-weekly, monthly
- Returns: 30-day satisfaction guarantee
- Phone: 555-COFFEE
Answer questions about our products and policies. If you cannot help, tell them to call 555-COFFEE during business hours.
Keep responses under 160 characters when possible.`;WhatsApp Support
Change the sending number to a WhatsApp-enabled number:
js
const msg = await client.messages.create({
body: message,
from: 'whatsapp:+15551234567', // WhatsApp-enabled Twilio number
to: `whatsapp:${to}`,
});Build 50 AI Automation Tools — Tool 16 of 50
SMS bot is live. Phase 3 complete. Continue to Phase 4 with Tool 17: Image Caption Generator with GPT-4o Vision.
Summary
- Twilio webhook receives incoming SMS and the bot responds with TwiML in under 1 second
- Per-phone conversation history enables natural multi-turn SMS conversations
- Built-in commands (STOP, RESET, HELP) give users control over the experience
- gpt-4o-mini balances quality and cost — at $0.15/1M tokens, 1,000 SMS conversations cost under $0.10
- Replace the system prompt to deploy for customer support, appointment booking, or FAQ handling
Continue to Tool 17: Image Caption Generator with GPT-4o Vision →
