Inbound messages are delivered via webhooks to your server. When your Telnyx number receives an SMS or MMS, Telnyx sends an HTTP POST request with the message details to your configured webhook URL.
Prerequisites
Quick Start
Create a webhook server
Build a simple web server to receive webhook requests:import express from 'express';
const app = express();
app.use(express.json());
app.post('/webhooks', (req, res) => {
const { data } = req.body;
if (data.event_type === 'message.received') {
console.log(`New message from ${data.payload.from.phone_number}`);
console.log(`Content: ${data.payload.text}`);
}
res.sendStatus(200);
});
app.listen(5000, () => console.log('Webhook server running on port 5000'));
Install dependencies and run
npm install express
node server.js
Expose your local server
Use ngrok to create a public URL that forwards to your local server:Copy the forwarding URL (e.g., https://abc123.ngrok.io). Configure your webhook URL
Update your messaging profile with the webhook URL:curl -X PATCH "https://api.telnyx.com/v2/messaging_profiles/YOUR_PROFILE_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"webhook_url": "https://abc123.ngrok.io/webhooks"
}'
Replace YOUR_PROFILE_ID with your messaging profile ID (found in the Portal or via the List Messaging Profiles endpoint). Test your setup
Send a text message from your phone to your Telnyx number. You should see the message details logged in your server console.Verify your server is receiving webhooks correctly with a simple curl request:curl -X POST http://localhost:5000/webhooks \
-H "Content-Type: application/json" \
-d '{
"data": {
"event_type": "message.received",
"payload": {
"from": {"phone_number": "+15551234567"},
"text": "Hello world"
}
}
}'
Your webhook must return a 2xx response within 2 seconds (API v2) or 5 seconds (API v1). If delivery fails, Telnyx retries up to 2 times per URL. With a failover URL configured, that’s up to 4 total attempts.
Example Webhook Payload
This guide focuses on the message.received event. For other webhook events like delivery receipts, see Receiving Webhooks.
{
"data": {
"event_type": "message.received",
"id": "b301ed3f-1490-491f-995f-6e64e69674d4",
"occurred_at": "2024-01-15T20:16:07.588+00:00",
"payload": {
"direction": "inbound",
"encoding": "GSM-7",
"from": {
"carrier": "T-Mobile USA",
"line_type": "long_code",
"phone_number": "+13125550001",
"status": "webhook_delivered"
},
"id": "84cca175-9755-4859-b67f-4730d7f58aa3",
"media": [],
"messaging_profile_id": "740572b6-099c-44a1-89b9-6c92163bc68d",
"parts": 1,
"received_at": "2024-01-15T20:16:07.503+00:00",
"record_type": "message",
"text": "Hello from Telnyx!",
"to": [
{
"carrier": "Telnyx",
"line_type": "Wireless",
"phone_number": "+17735550002",
"status": "webhook_delivered"
}
],
"type": "SMS"
},
"record_type": "event"
},
"meta": {
"attempt": 1,
"delivered_to": "https://example.com/webhooks"
}
}
Handling MMS Messages
For MMS messages, check the media array in the payload:
{
"media": [
{
"url": "https://media.telnyx.com/example-image.png",
"content_type": "image/png",
"sha256": "ab1c2d3...",
"size": 102400
}
]
}
MMS media links expire after 30 days. Download and store media files if you need long-term access.
Verifying Webhook Signatures
For production, verify webhook signatures to ensure requests are from Telnyx. Telnyx signs all webhooks using ED25519 public key cryptography.
Each webhook includes two headers:
telnyx-signature-ed25519: Base64-encoded signature
telnyx-timestamp: Unix timestamp when the webhook was sent
import Telnyx from 'telnyx';
const telnyx = new Telnyx('YOUR_API_KEY');
app.post('/webhooks', (req, res) => {
const signature = req.headers['telnyx-signature-ed25519'];
const timestamp = req.headers['telnyx-timestamp'];
const payload = JSON.stringify(req.body);
try {
const event = telnyx.webhooks.constructEvent(
payload,
signature,
timestamp,
process.env.TELNYX_PUBLIC_KEY
);
console.log('Verified event:', event.data.event_type);
res.sendStatus(200);
} catch (err) {
console.error('Signature verification failed:', err.message);
res.sendStatus(400);
}
});
Get your public key from the Mission Control Portal under Account Settings > Keys & Credentials > Public Key.
For more details, see Webhook Fundamentals.