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.

MMS Capabilities: Send up to 10 media attachments per message with a total size limit of 5MB. Media files are automatically optimized for carrier delivery while maintaining quality.

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
PDF .pdf 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

  1. Convert your media file to a byte array
  2. POST the file data to the Media API
  3. Receive a public SAS URL for the uploaded file (valid for 99 years)
  4. Include the URL in your MMS message request
Built-in Media Hosting: The API automatically handles file storage, generates secure URLs with SAS tokens, and maintains files for the lifetime of your account. No need to manage your own storage infrastructure!

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"
}
SAS Token URLs: The returned URI includes a SAS (Shared Access Signature) token that grants public read access for 99 years. Store this complete URL - you'll need it to send MMS messages.

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:

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

MMS Pricing: MMS messages cost more than SMS. Pricing varies by:
  • Number of attachments (1-3 segments for most MMS)
  • Total message size
  • Carrier (international MMS costs more)
Check your account dashboard for current MMS rates.

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

Video Optimization

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:

Carrier Limitations: Some carriers have additional restrictions on MMS:
  • File size limits may be lower (1-2MB)
  • Some formats may be blocked
  • International MMS may have poor support
Always test MMS delivery to your target carriers.

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"]
  }'

Next Steps