Media Attachments & MMS
Learn how to send multimedia messages (MMS) with images, videos, audio, and documents using the Approved Contact API. MMS messages allow you to create rich, engaging experiences that go beyond plain text.
Supported Formats
The API supports a wide variety of media formats. Files are automatically validated and converted as needed for optimal carrier compatibility.
Image Formats
| Format | Extension | MIME Type | Max Size |
|---|---|---|---|
| JPEG | .jpg, .jpeg | image/jpeg | 5MB |
| PNG | .png | image/png | 5MB |
| GIF | .gif | image/gif | 5MB |
| WebP | .webp | image/webp | 5MB |
Video Formats
| Format | Extension | MIME Type | Max Size |
|---|---|---|---|
| MP4 | .mp4 | video/mp4 | 5MB |
| MOV | .mov | video/quicktime | 5MB |
| AVI | .avi | video/x-msvideo | 5MB |
Audio Formats
| Format | Extension | MIME Type | Max Size |
|---|---|---|---|
| MP3 | .mp3 | audio/mpeg | 5MB |
| WAV | .wav | audio/wav | 5MB |
| AAC | .aac | audio/aac | 5MB |
Document Formats
| Format | Extension | MIME Type | Max Size |
|---|---|---|---|
| application/pdf | 5MB | ||
| Text | .txt | text/plain | 5MB |
| vCard | .vcf | text/vcard | 5MB |
Uploading Media
The Approved Contact API provides a media upload endpoint that stores your files in Azure Blob Storage and returns a secure, publicly accessible URL. This URL can then be used when sending MMS messages.
Upload Process
- Convert your media file to a byte array
- POST the file data to the Media API
- Receive a public SAS URL for the uploaded file (valid for 99 years)
- Include the URL in your MMS message request
Example: Upload an Image
# Base64 encode the image file data
BASE64_IMAGE=$(base64 -i image.jpg)
curl -X POST https://api.approvedcontact.com/api/v1/media \
-u "your-email@example.com:your-password" \
-H "Content-Type: application/json" \
-d "{
\"phoneNumber\": \"+15551234567\",
\"fileName\": \"product-image.jpg\",
\"contentType\": \"image/jpeg\",
\"data\": \"$BASE64_IMAGE\",
\"tenantId\": \"00000000-0000-0000-0000-000000000000\"
}"
import requests
import base64
# Read and convert file to byte array
with open('image.jpg', 'rb') as f:
file_bytes = f.read()
credentials = base64.b64encode(b'your-email@example.com:your-password').decode()
response = requests.post(
'https://api.approvedcontact.com/api/v1/media',
headers={'Authorization': f'Basic {credentials}'},
json={
'phoneNumber': '+15551234567',
'fileName': 'product-image.jpg',
'contentType': 'image/jpeg',
'data': list(file_bytes), # Convert bytes to array of integers
'tenantId': '00000000-0000-0000-0000-000000000000'
}
)
media_url = response.json()['uri']
print(f'Uploaded: {media_url}')
using System.Net.Http;
using System.Net.Http.Json;
using System.IO;
var client = new HttpClient();
var credentials = Convert.ToBase64String(
Encoding.ASCII.GetBytes("your-email@example.com:your-password"));
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", credentials);
// Read file as byte array
var imageBytes = await File.ReadAllBytesAsync("image.jpg");
var request = new
{
phoneNumber = "+15551234567",
fileName = "product-image.jpg",
contentType = "image/jpeg",
data = imageBytes,
tenantId = "00000000-0000-0000-0000-000000000000"
};
var response = await client.PostAsJsonAsync(
"https://api.approvedcontact.com/api/v1/media",
request
);
var result = await response.Content.ReadFromJsonAsync();
Console.WriteLine($"Uploaded: {result.Uri}");
const fs = require('fs');
const axios = require('axios');
// Read file as buffer and convert to byte array
const fileBuffer = fs.readFileSync('image.jpg');
const byteArray = Array.from(fileBuffer);
const credentials = Buffer.from('your-email@example.com:your-password').toString('base64');
axios.post(
'https://api.approvedcontact.com/api/v1/media',
{
phoneNumber: '+15551234567',
fileName: 'product-image.jpg',
contentType: 'image/jpeg',
data: byteArray,
tenantId: '00000000-0000-0000-0000-000000000000'
},
{
headers: { 'Authorization': `Basic ${credentials}` }
}
)
.then(response => {
console.log(`Uploaded: ${response.data.uri}`);
});
Upload Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
phoneNumber |
string | Yes | Phone number in E.164 format (must be provisioned) |
fileName |
string | Yes | Original filename with extension |
contentType |
string | Yes | MIME type (e.g., image/jpeg, video/mp4) |
data |
byte[] | Yes | File contents as byte array |
tenantId |
GUID | Yes | Your tenant identifier |
Upload Response
{
"uri": "https://youraccount.blob.core.windows.net/attachments/abc123/product-image.jpg?sv=2023-01-03&st=2025-01-11...",
"fileName": "product-image.jpg"
}
Alternative: Use Your Own Hosting
If you prefer to host media on your own infrastructure, you can provide any publicly accessible HTTPS URL
in the mediaUrls array when sending messages. Your URLs must:
- Be publicly accessible (no authentication)
- Use HTTPS protocol
- Have correct Content-Type headers
- Remain available until message delivery completes
Sending MMS Messages
After uploading media, include the URL(s) in the mediaUrls array when sending
a message. You can include up to 10 media attachments per message.
Example: Send MMS with Image
curl -X POST https://api.approvedcontact.com/api/v1/messages \
-u "your-email@example.com:your-password" \
-H "Content-Type: application/json" \
-d '{
"from": "+15551234567",
"to": ["+15559876543"],
"body": "Check out our new product!",
"mediaUrls": [
"https://storage.approvedcontact.com/attachments/abc123/product-image.jpg"
]
}'
Multiple Attachments
Send multiple media files in a single MMS:
{
"from": "+15551234567",
"to": ["+15559876543"],
"body": "Product gallery - 3 photos attached",
"mediaUrls": [
"https://storage.approvedcontact.com/attachments/abc123/image1.jpg",
"https://storage.approvedcontact.com/attachments/abc123/image2.jpg",
"https://storage.approvedcontact.com/attachments/abc123/image3.jpg"
]
}
Cost Considerations
- Number of attachments (1-3 segments for most MMS)
- Total message size
- Carrier (international MMS costs more)
Receiving Media Attachments
When someone sends an MMS message to your phone number, the webhook payload includes an
attachments array with URLs to download each media file.
Incoming MMS Webhook Payload
{
"messageId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"from": "+15551234567",
"message": "Here's the photo you requested",
"attachments": [
{
"name": "photo.jpg",
"url": "https://storage.approvedcontact.com/attachments/xyz789/photo.jpg",
"contentType": "image/jpeg",
"size": 512000
}
]
}
Downloading Received Media
Download and process received media files:
import requests
from pathlib import Path
def download_media(attachment):
response = requests.get(attachment['url'])
if response.status_code == 200:
# Save to disk
file_path = Path('downloads') / attachment['name']
file_path.parent.mkdir(exist_ok=True)
with open(file_path, 'wb') as f:
f.write(response.content)
print(f"Downloaded: {file_path}")
return file_path
return None
# Process webhook
@app.route('/webhooks/messages', methods=['POST'])
def handle_webhook():
message = request.get_json()
for attachment in message.get('attachments', []):
file_path = download_media(attachment)
# Process the file...
return jsonify({'success': True}), 200
public async Task DownloadMediaAsync(Attachment attachment)
{
using var client = new HttpClient();
var response = await client.GetAsync(attachment.Url);
if (response.IsSuccessStatusCode)
{
var directory = Path.Combine("downloads");
Directory.CreateDirectory(directory);
var filePath = Path.Combine(directory, attachment.Name);
var bytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync(filePath, bytes);
Console.WriteLine($"Downloaded: {filePath}");
return filePath;
}
return null;
}
// Process webhook
[HttpPost("webhooks/messages")]
public async Task HandleWebhook([FromBody] IncomingMessage message)
{
foreach (var attachment in message.Attachments ?? Array.Empty())
{
var filePath = await DownloadMediaAsync(attachment);
// Process the file...
}
return Ok();
}
const fs = require('fs');
const path = require('path');
const axios = require('axios');
async function downloadMedia(attachment) {
const response = await axios.get(attachment.url, {
responseType: 'arraybuffer'
});
const dir = 'downloads';
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
const filePath = path.join(dir, attachment.name);
fs.writeFileSync(filePath, response.data);
console.log(`Downloaded: ${filePath}`);
return filePath;
}
// Process webhook
app.post('/webhooks/messages', async (req, res) => {
const message = req.body;
for (const attachment of message.attachments || []) {
const filePath = await downloadMedia(attachment);
// Process the file...
}
res.json({ success: true });
});
Optimization Tips
Image Optimization
- Compress Images: Use tools like TinyPNG or ImageOptim before uploading
- Resize for Mobile: 1024x1024px is typically sufficient for MMS
- Use JPEG: Best compression for photos (60-80% quality)
- Use PNG: Best for graphics, screenshots, and text
Video Optimization
- Keep It Short: Aim for 10-15 seconds max
- Reduce Resolution: 480p or 720p is sufficient
- Use H.264 Codec: Best compatibility across carriers
- Compress Video: Use FFmpeg or HandBrake to reduce file size
Example: FFmpeg Video Compression
# Compress video for MMS (target 3-4MB)
ffmpeg -i input.mp4 -vcodec h264 -acodec aac \
-vf scale=640:480 -b:v 500k -b:a 128k \
-movflags +faststart output.mp4
Troubleshooting
Common Issues
File Too Large
Error: Media file exceeds maximum size of 5MB
Solution: Compress or resize the file before uploading.
Unsupported Format
Error: Unsupported media type: image/bmp
Solution: Convert to a supported format (JPEG, PNG, GIF).
Upload Timeout
Error: Request timeout while uploading media
Solution: Check your internet connection and retry. Consider compressing large files.
MMS Not Delivered
Problem: SMS delivers but MMS fails
Solutions:
- Verify recipient's device supports MMS
- Check recipient has mobile data enabled
- Ensure media URLs are publicly accessible
- Verify phone number is MMS-capable
- File size limits may be lower (1-2MB)
- Some formats may be blocked
- International MMS may have poor support
Testing
Test MMS delivery with different file types and sizes:
# Test with small image
curl -X POST https://api.approvedcontact.com/api/v1/messages \
-u "your-email@example.com:your-password" \
-H "Content-Type: application/json" \
-d '{
"from": "+15551234567",
"to": ["+YOUR_TEST_NUMBER"],
"body": "Test MMS - Image",
"mediaUrls": ["https://via.placeholder.com/150"]
}'