Skip to main content

Messaging Integration

Process SMS/MMS messages, implement auto-responses, and handle messaging workflows with Edge Compute functions.

Message Processing

Handle incoming messaging webhooks:

export default async function(request) {
const webhook = await request.json();

switch (webhook.event_type) {
case 'message.received':
return await handleMessageReceived(webhook);
case 'message.sent':
return await handleMessageSent(webhook);
case 'message.finalized':
return await handleMessageFinalized(webhook);
default:
return new Response('OK', { status: 200 });
}
}

async function handleMessageReceived(webhook) {
const message = webhook.data.payload;
const fromNumber = message.from.phone_number;
const messageBody = message.text;

// Process the message
console.log(`Received message from ${fromNumber}: ${messageBody}`);

// Trigger auto-response if needed
if (shouldAutoReply(messageBody)) {
await sendAutoReply(fromNumber, messageBody);
}

return new Response('Message processed', { status: 200 });
}

Auto-Response System

Implement intelligent auto-responses:

import re
import json
import aiohttp

async def handler(request):
webhook = await request.json()

if webhook['event_type'] != 'message.received':
return {"status": "ignored"}

message = webhook['data']['payload']
from_number = message['from']['phone_number']
text = message['text'].lower().strip()

# Auto-response logic
response_text = generate_auto_response(text)

if response_text:
await send_message(from_number, response_text)

return {"status": "processed"}

def generate_auto_response(text):
"""Generate contextual auto-responses."""

# Business hours check.
if any(word in text for word in ['hours', 'open', 'closed']):
return "We're open Monday-Friday 9AM-6PM EST. Text HELP for more options."

# Support keywords.
if any(word in text for word in ['help', 'support', 'problem', 'issue']):
return "Thanks for reaching out! Our support team will respond within 2 hours. For urgent issues, call (555) 123-4567."

# Pricing inquiries.
if any(word in text for word in ['price', 'cost', 'pricing', 'plan']):
return "Visit our pricing page: https://example.com/pricing or reply DEMO for a free demo."

# Order status.
if any(word in text for word in ['order', 'status', 'tracking', 'delivery']):
return "Please provide your order number and we'll check the status for you."

# General inquiry.
if text.endswith('?'):
return "Thanks for your question! Our team will respond shortly. Reply URGENT if this needs immediate attention."

# Default acknowledgment.
return "Message received! We'll get back to you soon."

async def send_message(to_number, text):
"""Send SMS via Telnyx API."""
url = "https://api.telnyx.com/v2/messages"
headers = {
'Authorization': f'Bearer {os.environ["TELNYX_API_KEY"]}',
'Content-Type': 'application/json'
}
data = {
'from': os.environ['FROM_PHONE_NUMBER'],
'to': to_number,
'text': text
}

async with aiohttp.ClientSession() as session:
async with session.post(url, headers=headers, json=data) as response:
if response.status == 200:
print(f"Auto-reply sent to {to_number}")
else:
print(f"Failed to send reply: {response.status}")

Message Broadcasting

Send messages to multiple recipients efficiently:

package main

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"sync"
)

type BroadcastRequest struct {
Recipients []string `json:"recipients"`
Message string `json:"message"`
ScheduleAt string `json:"schedule_at,omitempty"`
}

type MessagePayload struct {
From string `json:"from"`
To string `json:"to"`
Text string `json:"text"`
}

func handler(w http.ResponseWriter, r *http.Request) {
var request BroadcastRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
http.Error(w, "Invalid request body", 400)
return
}

// Send messages concurrently
results := broadcastMessage(request.Recipients, request.Message)

response := map[string]interface{}{
"total": len(request.Recipients),
"sent": results.Sent,
"failed": results.Failed,
"message": "Broadcast completed",
}

json.NewEncoder(w).Encode(response)
}

type BroadcastResults struct {
Sent int
Failed int
}

func broadcastMessage(recipients []string, message string) BroadcastResults {
var wg sync.WaitGroup
var mu sync.Mutex
results := BroadcastResults{}

// Process in batches to avoid rate limits
batchSize := 10
for i := 0; i < len(recipients); i += batchSize {
end := i + batchSize
if end > len(recipients) {
end = len(recipients)
}

batch := recipients[i:end]

for _, recipient := range batch {
wg.Add(1)
go func(to string) {
defer wg.Done()

if sendSMS(to, message) {
mu.Lock()
results.Sent++
mu.Unlock()
} else {
mu.Lock()
results.Failed++
mu.Unlock()
}
}(recipient)
}

wg.Wait() // Wait for batch to complete before next batch
}

return results
}

func sendSMS(to, text string) bool {
payload := MessagePayload{
From: os.Getenv("FROM_PHONE_NUMBER"),
To: to,
Text: text,
}

jsonData, _ := json.Marshal(payload)

req, _ := http.NewRequest("POST", "https://api.telnyx.com/v2/messages", bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TELNYX_API_KEY"))
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return false
}
defer resp.Body.Close()

return resp.StatusCode == 200
}

Compliance Handling

Handle 10DLC compliance and opt-out management:

// Compliance and opt-out management
const optOutKeywords = ['STOP', 'QUIT', 'UNSUBSCRIBE', 'CANCEL', 'END', 'REMOVE'];
const optInKeywords = ['START', 'YES', 'SUBSCRIBE', 'JOIN'];

export default async function(request) {
const webhook = await request.json();

if (webhook.event_type !== 'message.received') {
return new Response('OK', { status: 200 });
}

const message = webhook.data.payload;
const phoneNumber = message.from.phone_number;
const messageText = message.text.toUpperCase().trim();

// Handle opt-out requests
if (optOutKeywords.includes(messageText)) {
await handleOptOut(phoneNumber);
await sendOptOutConfirmation(phoneNumber);
return new Response('Opt-out processed', { status: 200 });
}

// Handle opt-in requests
if (optInKeywords.includes(messageText)) {
await handleOptIn(phoneNumber);
await sendOptInConfirmation(phoneNumber);
return new Response('Opt-in processed', { status: 200 });
}

// Check if user is opted in before processing
const isOptedIn = await checkOptInStatus(phoneNumber);
if (!isOptedIn) {
// Don't process messages from opted-out users
return new Response('User opted out', { status: 200 });
}

// Process normal message
return await processMessage(message);
}

async function handleOptOut(phoneNumber) {
// Add to opt-out database
await fetch('https://your-api.com/opt-out', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
phone_number: phoneNumber,
opted_out_at: new Date().toISOString()
})
});

console.log(`User ${phoneNumber} opted out`);
}

async function sendOptOutConfirmation(phoneNumber) {
await sendMessage(phoneNumber, 'You have been unsubscribed. Reply START to opt back in.');
}

async function handleOptIn(phoneNumber) {
// Remove from opt-out database
await fetch(`https://your-api.com/opt-out/${encodeURIComponent(phoneNumber)}`, {
method: 'DELETE'
});

console.log(`User ${phoneNumber} opted in`);
}

async function sendOptInConfirmation(phoneNumber) {
await sendMessage(phoneNumber, 'Welcome back! You are now subscribed to our messages. Reply STOP to opt out anytime.');
}

async function sendMessage(to, text) {
const response = await fetch('https://api.telnyx.com/v2/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.TELNYX_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: process.env.FROM_PHONE_NUMBER,
to: to,
text: text
})
});

return response.ok;
}

Explore more messaging features in our Messaging API documentation.