Send multimedia messages (images, video, audio, vCards) via the Telnyx API and process inbound MMS attachments from webhooks.
Prerequisites
MMS is supported on US/Canada long codes, toll-free, and short codes. For media format details and carrier limits, see MMS Media & Transcoding .
Send an MMS
Include media_urls in your message request. You can send up to 10 media files per message.
Python
Node
Ruby
Java
.NET
PHP
Go
curl
import telnyx
telnyx.api_key = "YOUR_API_KEY"
message = telnyx.Message.create(
from_ = "+18005550100" ,
to = "+18005550101" ,
text = "Here's the photo you requested!" ,
media_urls = [ "https://example.com/image.jpg" ],
messaging_profile_id = "YOUR_MESSAGING_PROFILE_ID"
)
print ( f "Message ID: { message.id } " )
print ( f "Status: { message.to[ 0 ][ 'status' ] } " )
Include multiple URLs in media_urls. Total payload must stay under carrier limits.
curl -X POST https://api.telnyx.com/v2/messages \
-H "Authorization: Bearer $TELNYX_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"from": "+18005550100",
"to": "+18005550101",
"text": "Product photos attached",
"media_urls": [
"https://example.com/photo1.jpg",
"https://example.com/photo2.jpg",
"https://example.com/photo3.jpg"
],
"messaging_profile_id": "YOUR_MESSAGING_PROFILE_ID"
}'
Media URLs must be publicly accessible. Telnyx downloads the media at send time — if the URL requires authentication or returns an error, the message will fail.
Receive an MMS
Inbound MMS messages arrive as webhooks to your messaging profile’s webhook URL. The media array contains attachment details.
Webhook payload
{
"data" : {
"event_type" : "message.received" ,
"payload" : {
"from" : { "phone_number" : "+18005550101" },
"to" : [{ "phone_number" : "+18005550100" }],
"text" : "Check out this photo!" ,
"media" : [
{
"url" : "https://media.telnyx.com/abc123/image.jpg" ,
"content_type" : "image/jpeg" ,
"size" : 245760
}
]
}
}
}
Media URLs are ephemeral. Telnyx-hosted media links expire. Download and store attachments in your own storage immediately upon receipt.
Process inbound MMS
from flask import Flask, request, jsonify
import requests
import os
app = Flask( __name__ )
TELNYX_API_KEY = os.getenv( "TELNYX_API_KEY" )
MEDIA_DIR = "./received_media"
os.makedirs( MEDIA_DIR , exist_ok = True )
@app.route ( "/webhooks" , methods = [ "POST" ])
def webhooks ():
body = request.json
event_type = body[ "data" ][ "event_type" ]
if event_type != "message.received" :
return jsonify({ "status" : "ignored" }), 200
payload = body[ "data" ][ "payload" ]
from_number = payload[ "from" ][ "phone_number" ]
text = payload.get( "text" , "" )
media = payload.get( "media" , [])
print ( f "From: { from_number } | Text: { text } | Attachments: { len (media) } " )
# Download each attachment
saved_files = []
for item in media:
resp = requests.get(item[ "url" ])
ext = item[ "content_type" ].split( "/" )[ - 1 ]
filename = f " { MEDIA_DIR } / { from_number } _ { len (saved_files) } . { ext } "
with open (filename, "wb" ) as f:
f.write(resp.content)
saved_files.append(filename)
print ( f " Saved: { filename } ( { item[ 'size' ] } bytes)" )
return jsonify({ "status" : "ok" , "files" : len (saved_files)}), 200
if __name__ == "__main__" :
app.run( port = 8000 )
Echo received media back to the sender, or reply with different media:
import telnyx
import os
telnyx.api_key = os.getenv( "TELNYX_API_KEY" )
def handle_mms_webhook ( payload ):
"""Reply to inbound MMS with the same media + a text response."""
from_number = payload[ "from" ][ "phone_number" ]
to_number = payload[ "to" ][ 0 ][ "phone_number" ]
media = payload.get( "media" , [])
# Reply with the same media echoed back
media_urls = [item[ "url" ] for item in media]
reply = telnyx.Message.create(
from_ = to_number,
to = from_number,
text = f "Thanks! Received { len (media) } attachment(s)." ,
media_urls = media_urls if media_urls else None ,
messaging_profile_id = "YOUR_MESSAGING_PROFILE_ID"
)
print ( f "Reply sent: { reply.id } " )
Type Formats Max Size Images JPEG, PNG, GIF, BMP, WebP 1 MB (carrier-dependent) Video MP4, 3GP 600 KB (carrier-dependent) Audio MP3, AMR, WAV, OGG 600 KB (carrier-dependent) Files vCard (.vcf), PDF 600 KB
Telnyx automatically transcodes oversized media when possible. For details on carrier-specific limits and transcoding behavior, see MMS Media & Transcoding .
For production use, store received media in your own cloud storage rather than relying on ephemeral Telnyx URLs.
import boto3
import requests
from urllib.parse import urlparse
s3 = boto3.client( "s3" )
BUCKET = "your-mms-bucket"
def save_to_s3 ( media_url , from_number , index ):
resp = requests.get(media_url)
content_type = resp.headers.get( "content-type" , "application/octet-stream" )
ext = content_type.split( "/" )[ - 1 ]
key = f "mms/ { from_number } / { index } . { ext } "
s3.put_object(
Bucket = BUCKET ,
Key = key,
Body = resp.content,
ContentType = content_type
)
return f "s3:// { BUCKET } / { key } "
Upload to Google Cloud Storage
from google.cloud import storage
import requests
gcs = storage.Client()
bucket = gcs.bucket( "your-mms-bucket" )
def save_to_gcs ( media_url , from_number , index ):
resp = requests.get(media_url)
content_type = resp.headers.get( "content-type" , "application/octet-stream" )
ext = content_type.split( "/" )[ - 1 ]
blob = bucket.blob( f "mms/ { from_number } / { index } . { ext } " )
blob.upload_from_string(resp.content, content_type = content_type)
return blob.public_url
Troubleshooting
MMS sent but recipient receives SMS only
Cause: The media URL was unreachable, or the recipient’s carrier doesn’t support MMS.Fix:
Verify the media URL is publicly accessible (no auth required)
Check message detail records for error details
Confirm the recipient’s number supports MMS
Media too large — message rejected
Inbound media URL returns 404
Cause: Telnyx media URLs are temporary. You waited too long to download.Fix: Download media immediately in your webhook handler. Store in your own S3/GCS bucket.
MMS not supported on my number
Cause: Some number types (e.g., alphanumeric sender IDs) don’t support MMS.Fix: Use a US/Canada long code, toll-free, or short code with MMS enabled in your messaging profile .
Next steps