Transform your Android phone into a full two-way SMS gateway. Forward every incoming SMS to your server and auto-reply programmatically — build chatbots, support flows, and AI-powered SMS automation. No third-party provider needed.
The complete flow from incoming SMS to your server and back — in under a second.
{"sms_text": "your reply"} to auto-respond. Return HTTP 200 with an empty body if no reply is needed. The same endpoint also receives outgoing SMS delivery status updates (differentiate using the type field).
Your server receives this JSON payload for every incoming SMS.
{
"type": "incoming_sms",
"sender": "+40721000000",
"message": "Hi, I need help with my order",
"timestamp": 1707400000000,
"conversation_history": [
{ "role": "out", "message": "Your order #1234 has shipped!", "timestamp": 1707399000000 },
{ "role": "in", "message": "Hi, I need help with my order", "timestamp": 1707400000000 }
]
}
message again. Requires Conversation History enabled in Settings (0 / 5 / 10 / 20 / 50 messages).
HTTP 200
Content-Type: application/json
{ "sms_text": "Thanks! Our support team will contact you shortly." }
Production-ready auto-responder implementations.
const express = require('express');
const app = express();
app.use(express.json());
app.post('/sms-webhook', (req, res) => {
const { type, sender, message, conversation_history, smsId, status } = req.body;
// Secure your endpoint
if (req.headers['x-api-key'] !== 'your-secret-key') {
return res.status(401).json({ error: 'Unauthorized' });
}
if (type === 'incoming_sms') {
console.log(`📩 SMS from ${sender}: ${message}`);
// Keyword-based auto-reply
if (message.toLowerCase().includes('help')) {
return res.json({
sms_text: 'Support hours: Mon-Fri 9AM-5PM. Reply URGENT for immediate help.'
});
}
if (message.toLowerCase().includes('urgent')) {
return res.json({
sms_text: 'An agent will contact you within 10 minutes.'
});
}
// No reply needed
return res.status(200).send();
}
if (type === 'sms_status') {
console.log(`📊 SMS ${smsId} → ${status}`);
}
res.status(200).send();
});
app.listen(3000, () => console.log('Webhook server running on :3000'));
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/sms-webhook', methods=['POST'])
def sms_webhook():
if request.headers.get('X-API-Key') != 'your-secret-key':
return jsonify({'error': 'Unauthorized'}), 401
data = request.json
msg_type = data.get('type')
if msg_type == 'incoming_sms':
sender = data['sender']
message = data['message']
history = data.get('conversation_history', [])
print(f"📩 SMS from {sender}: {message} (history: {len(history)} msgs)")
# Keyword-based auto-reply
if 'help' in message.lower():
return jsonify({
'sms_text': 'Support hours: Mon-Fri 9AM-5PM. Reply URGENT for immediate help.'
})
# No reply
return '', 200
if msg_type == 'sms_status':
print(f"📊 SMS {data['smsId']} → {data['status']}")
return '', 200
if __name__ == '__main__':
app.run(port=3000)
const express = require('express');
const OpenAI = require('openai');
const app = express();
app.use(express.json());
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
app.post('/sms-webhook', async (req, res) => {
const { type, sender, message, conversation_history } = req.body;
if (req.headers['x-api-key'] !== 'your-secret-key') {
return res.status(401).json({ error: 'Unauthorized' });
}
if (type === 'incoming_sms') {
const messages = [
{ role: 'system', content: 'You are a helpful SMS assistant. Keep replies under 160 characters.' }
];
if (conversation_history && conversation_history.length > 0) {
// conversation_history already contains the current message as the last "in" entry
conversation_history.forEach(msg => {
messages.push({
role: msg.role === 'in' ? 'user' : 'assistant',
content: msg.message
});
});
} else {
messages.push({ role: 'user', content: message });
}
try {
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages,
max_tokens: 100
});
return res.json({ sms_text: completion.choices[0].message.content });
} catch (err) {
console.error('OpenAI error:', err);
return res.json({ sms_text: 'Sorry, please try again later.' });
}
}
if (type === 'sms_status') {
console.log(`📊 SMS ${req.body.smsId} → ${req.body.status}`);
}
res.status(200).send();
});
app.listen(3000);
from flask import Flask, request, jsonify
from openai import OpenAI
app = Flask(__name__)
client = OpenAI() # uses OPENAI_API_KEY env var
@app.route('/sms-webhook', methods=['POST'])
def sms_webhook():
if request.headers.get('X-API-Key') != 'your-secret-key':
return jsonify({'error': 'Unauthorized'}), 401
data = request.json
if data.get('type') == 'incoming_sms':
messages = [
{'role': 'system', 'content': 'You are a helpful SMS assistant. Keep replies under 160 characters.'}
]
history = data.get('conversation_history', [])
if history:
# conversation_history already contains the current message as last "in" entry
for msg in history:
role = 'user' if msg['role'] == 'in' else 'assistant'
messages.append({'role': role, 'content': msg['message']})
else:
messages.append({'role': 'user', 'content': data['message']})
try:
completion = client.chat.completions.create(
model='gpt-4o-mini',
messages=messages,
max_tokens=100
)
reply = completion.choices[0].message.content
return jsonify({'sms_text': reply})
except Exception as e:
print(f'OpenAI error: {e}')
return jsonify({'sms_text': 'Sorry, please try again later.'})
if data.get('type') == 'sms_status':
print(f"📊 SMS {data['smsId']} → {data['status']}")
return '', 200
if __name__ == '__main__':
app.run(port=3000)
What you can build with two-way SMS automation.
Connect incoming SMS to OpenAI, Claude, or Gemini. Include conversation history for context-aware, multi-turn conversations entirely via SMS — no app required for customers.
Auto-reply with FAQ answers based on keywords. Escalate complex queries to a human agent. Log all SMS conversations in your CRM automatically.
Send "Your appointment is tomorrow at 10AM. Reply YES to confirm or NO to cancel." Process the reply and update your booking system automatically.
Forward OTP codes received on your Android to your backend for automated 2FA verification flows. Great for testing or server-side auth automation.
Ask customers to rate their experience (reply 1–5). Capture the reply on your server and store it in your analytics or CRM with zero manual work.
Customers text their order number — your server looks it up and auto-replies with the current status. Real-time, no app needed, works on any phone.
type: "incoming_sms") and delivery status updates (type: "sms_status").{"sms_text": "reply"} from your endpoint. For AI-powered replies, pass the conversation_history array directly to OpenAI or Claude — it already includes the current message as the last entry.sms_text field is optional — only include it when you want the app to send a reply back to the sender.conversation_history array is included in every webhook payload with both sent ("out") and received ("in") messages, sorted oldest → newest. The current incoming message is already the last entry.X-API-Key header with every webhook request. Validate it in your server code to reject unauthorized requests.7-day free trial. 100 SMS/day. No credit card required.