Receive Inbound SMS
Handle inbound SMS messages on your CloudVNO phone numbers using webhooks.
How Inbound SMS Works
When someone sends an SMS to your CloudVNO phone number, CloudVNO forwards the message to your configured webhook URL via HTTP POST.
Configure Your Webhook
- In the dashboard, go to Phone Numbers
- Click on the number you want to configure
- Under Messaging, set the Webhook URL for inbound messages
- Set the HTTP method (POST recommended)
Or configure via API:
number = client.incoming_phone_numbers("+14155551234").update(
sms_url="https://yourapp.com/sms-webhook",
sms_method="POST"
)
Handle the Webhook
CloudVNO sends these parameters to your webhook:
| Parameter | Description |
|---|---|
MessageSid | Unique ID for this message |
From | Sender's phone number |
To | Your CloudVNO number |
Body | Message text |
NumMedia | Number of media attachments |
MediaUrl0 | URL of first media attachment (if any) |
from flask import Flask, request, Response
app = Flask(__name__)
@app.route("/sms-webhook", methods=["POST"])
def sms_webhook():
from_number = request.form["From"]
body = request.form["Body"]
print(f"Received SMS from {from_number}: {body}")
# Auto-reply
if body.strip().upper() == "HELLO":
return Response(
'<?xml version="1.0" encoding="UTF-8"?>'
'<Response><Message>Hi there! How can we help?</Message></Response>',
mimetype="text/xml"
)
return Response("", status=204)
import express from 'express';
const app = express();
app.use(express.urlencoded({ extended: false }));
app.post('/sms-webhook', (req, res) => {
const { From, Body } = req.body;
console.log(`SMS from ${From}: ${Body}`);
res.status(204).send();
});
Webhook Security
Validate that incoming requests are genuinely from CloudVNO by checking the X-CloudVNO-Signature header:
from cloudvno.security import validate_signature
@app.route("/sms-webhook", methods=["POST"])
def sms_webhook():
signature = request.headers.get("X-CloudVNO-Signature")
valid = validate_signature(
auth_token=os.environ["CLOUDVNO_AUTH_TOKEN"],
signature=signature,
url=request.url,
params=request.form
)
if not valid:
return Response("Forbidden", status=403)
# Handle message...