Skip to content

How to build an AI agent that handles spam text messages

Problem

When I tried to build an automated SMS spam handler, I got this error:

Error: Invalid API endpoint. The `/sms-webhook` endpoint is not receiving requests.

The scam texts kept coming in, but my AI agent wasn’t responding. I spent hours debugging why the webhook wasn’t working.

Environment

  • Node.js 18.x
  • Express.js 4.x
  • Twilio API 8.x
  • OpenAI GPT-3.5-turbo

What happened?

I was getting flooded with scam text messages like:

"URGENT: Your package delivery failed. Click here to reschedule: [scam link]"
"You've won a free iPhone! Claim now before it's gone!"
"Bank security alert. Please verify your account immediately."

I tried to build a simple filter, but the scammers kept finding ways around it. So I decided to fight back by wasting their time with an AI agent.

Here’s my initial setup:

sms-webhook.js
app.post('/sms-webhook', async (req, res) => {
const message = req.body.Body;
const from = req.body.From;
const to = req.body.To;
// Simple check for spam keywords
if (isSpam(message)) {
console.log('Blocked spam:', message);
return res.status(200).send('OK');
}
// Send response
const response = await handleIncomingSMS(from, to, message);
await twilio.messages.create({
body: response,
from: to,
to: from
});
res.status(200).send('OK');
});

The isSpam function was too basic. It only checked for obvious keywords that scammers quickly learned to avoid.

But when I deployed this, my webhook logs showed no incoming requests. The scam texts were still coming through to my phone, but my server wasn’t receiving them.

How to solve it?

I tried adding debug logging to see what was happening:

debug-webhook.js
app.post('/sms-webhook', async (req, res) => {
console.log('Webhook received:', req.body);
console.log('Headers:', req.headers);
const message = req.body.Body;
const from = req.body.From;
const to = req.body.To;
console.log(`Received message from ${from}: ${message}`);
if (isSpam(message)) {
console.log('Blocked spam:', message);
return res.status(200).send('OK');
}
const response = await handleIncomingSMS(from, to, message);
await twilio.messages.create({
body: response,
from: to,
to: from
});
res.status(200).send('OK');
});

I could see the webhook wasn’t being called at all. The issue was with my Twilio configuration - I had set the webhook to the wrong URL.

Then I updated the Twilio configuration to use the correct URL:

twilio-setup.js
// Set webhook URL
await twilio.messages.create({
body: 'Hello from AI agent',
from: twilioPhoneNumber,
to: myPersonalNumber,
statusCallback: 'https://myserver.com/sms-webhook'
});

Now test again:

Webhook received: { Body: 'URGENT: Your package...', From: '+1234567890', To: '+0987654321' }
Received message from +1234567890: URGENT: Your package...

You can see that I succeeded to receive the webhook requests.

The reason

I think the key reason for the error is:

  1. Wrong webhook URL configuration in Twilio dashboard
  2. Missing proper error handling in the webhook endpoint
  3. Simple spam detection that gets bypassed easily

The real solution wasn’t just fixing the webhook - it was building an AI agent that could waste scammer time effectively.

Building the AI Agent

Here’s my complete AI spam handler:

ai-spam-agent.js
class SpamAgent {
constructor(llmClient) {
this.llm = llmClient;
this.conversationHistory = new Map();
}
async handleSMS(from, message) {
const context = this.getConversationContext(from);
const systemPrompt = this.createSystemPrompt();
const fullPrompt = `
${systemPrompt}
CONVERSATION HISTORY:
${context}
NEW MESSAGE:
${message}
RESPONSE:
`;
const response = await this.llm.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: fullPrompt }],
max_tokens: 150,
temperature: 0.8
});
const reply = response.choices[0].message.content;
this.updateConversation(from, message, reply);
return reply;
}
createSystemPrompt() {
return `You are a slightly distracted but friendly person who is slow to understand things.
You like to give detailed responses about your daily activities.
When scammers ask for personal information, you make excuses about blurry vision,
being busy, or not understanding. Keep responses under 100 characters.`;
}
getConversationContext(sender) {
const history = this.conversationHistory.get(sender) || [];
return history.slice(-5).map(msg => `${msg.sender}: ${msg.text}`).join('\n');
}
updateConversation(sender, message, response) {
if (!this.conversationHistory.has(sender)) {
this.conversationHistory.set(sender, []);
}
const history = this.conversationHistory.get(sender);
history.push(
{ sender: 'user', text: message, timestamp: Date.now() },
{ sender: 'ai', text: response, timestamp: Date.now() }
);
// Keep only last 10 messages
if (history.length > 10) {
history.splice(0, 2);
}
}
}

The Creative Tactics

The real power is in wasting scammer time. Here are the tactics I used:

Random Status Updates

status-updates.js
const STATUS_UPDATES = [
"I'm at the red light now, there's a very handsome squirrel on the sidewalk",
"Just grabbing coffee, the line is super long today",
"Stuck in traffic, watching two cars argue over parking",
"At the grocery store, they just announced they're out of my favorite cereal",
"Walking the dog, he found a stick that's almost as big as him"
];
function generateStatusUpdate() {
const randomDelay = 60000 + Math.random() * 120000; // 1-3 minutes
const update = STATUS_UPDATES[Math.floor(Math.random() * STATUS_UPDATES.length)];
return {
response: update,
delay: randomDelay
};
}

Captcha Excuses

captcha-handler.js
async function handleCaptchaChallenge() {
const excuses = [
"Sorry my eyes are blurry from looking at screens all day",
"I can't see it clearly, my glasses are dirty",
"The image is loading slowly on my phone",
"I can't read it, the lighting is bad here",
"Let me find my glasses, I think I left them somewhere"
];
const delay = 30000 + Math.random() * 60000; // 30-90 seconds
return {
response: excuses[Math.floor(Math.random() * excuses.length)],
delay: delay
};
}

Real Results

After running this for a week, here’s what happened:

AI conversations with scammers: 47
Total cost: $1.42
Time wasted by scammers: ~6 hours
Status updates sent: 23
Captcha excuses used: 12

One scammer actually responded to my squirrel story:

Scammer: “Can you focus? This is important” AI: “The squirrel is waving at me now, I have to wave back”

Architecture Overview

┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SMS │ ──→ │ Webhook │ ──→ │ AI Agent │
│ Gateway │ │ Server │ │ (GPT-3.5) │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
└──────────────────┼──────────────────┘
┌─────────────┐
│ Database │
│ (SQLite) │
└─────────────┘

Cost Optimization

The key to keeping costs low:

  1. Use GPT-3.5-turbo instead of GPT-4
  2. Keep conversations under 5 messages
  3. Implement timeouts after 30 minutes
  4. Use free tiers for hosting

Total weekly cost breakdown:

  • SMS Gateway: $1.00
  • OpenAI API: $0.42
  • Hosting: $0.00 (using free tier)

Summary

In this post, I showed how to build an AI agent that fights back against SMS scammers. The key point is that you can waste scammer time effectively while collecting intelligence about their tactics. The system costs less than $2 per week and turns the tables on scammers by making them waste their time on you instead.

The real benefit is not just blocking spam - it’s making the scammer’s work less profitable by increasing their time cost per victim.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments