WhatsApp API Media Handling

Panduan lengkap kirim dan terima media via WhatsApp API. Gambar, video, dokumen, audio. Upload, download, best practices!

WhatsApp API Media Handling
WhatsApp API Media Handling

Media bikin pesan lebih engaging!

WhatsApp API mendukung berbagai jenis media - gambar, video, audio, dokumen, dan sticker. Panduan ini menjelaskan cara kirim dan terima media dengan benar.


Jenis Media yang Didukung

📁 SUPPORTED MEDIA:

IMAGE:
- Format: JPEG, PNG
- Max size: 5 MB
- Recommended: < 1 MB

VIDEO:
- Format: MP4, 3GP
- Max size: 16 MB
- Codec: H.264, AAC

AUDIO:
- Format: AAC, MP3, MP4, AMR, OGG
- Max size: 16 MB

DOCUMENT:
- Format: PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX
- Max size: 100 MB

STICKER:
- Format: WebP
- Max size: 100 KB (static), 500 KB (animated)
- Size: 512x512 pixels

Kirim Media

Kirim Image:

javascript

const axios = require('axios');

const PHONE_NUMBER_ID = process.env.PHONE_NUMBER_ID;
const ACCESS_TOKEN = process.env.ACCESS_TOKEN;

// Option 1: Via URL (lebih mudah)
async function sendImageUrl(to, imageUrl, caption = '') {
    const url = `https://graph.facebook.com/v17.0/${PHONE_NUMBER_ID}/messages`;
    
    const payload = {
        messaging_product: 'whatsapp',
        to: to,
        type: 'image',
        image: {
            link: imageUrl,
            caption: caption
        }
    };
    
    const response = await axios.post(url, payload, {
        headers: {
            'Authorization': `Bearer ${ACCESS_TOKEN}`,
            'Content-Type': 'application/json'
        }
    });
    
    return response.data;
}

// Usage
await sendImageUrl(
    '628123456789',
    'https://brand.com/product.jpg',
    'Produk terbaru kami! 🛍️'
);

Upload Media Dulu:

javascript

const FormData = require('form-data');
const fs = require('fs');

// Step 1: Upload media
async function uploadMedia(filePath, mimeType) {
    const url = `https://graph.facebook.com/v17.0/${PHONE_NUMBER_ID}/media`;
    
    const form = new FormData();
    form.append('file', fs.createReadStream(filePath));
    form.append('type', mimeType);
    form.append('messaging_product', 'whatsapp');
    
    const response = await axios.post(url, form, {
        headers: {
            'Authorization': `Bearer ${ACCESS_TOKEN}`,
            ...form.getHeaders()
        }
    });
    
    return response.data.id; // Media ID
}

// Step 2: Kirim dengan Media ID
async function sendImageById(to, mediaId, caption = '') {
    const url = `https://graph.facebook.com/v17.0/${PHONE_NUMBER_ID}/messages`;
    
    const payload = {
        messaging_product: 'whatsapp',
        to: to,
        type: 'image',
        image: {
            id: mediaId,
            caption: caption
        }
    };
    
    const response = await axios.post(url, payload, {
        headers: {
            'Authorization': `Bearer ${ACCESS_TOKEN}`,
            'Content-Type': 'application/json'
        }
    });
    
    return response.data;
}

// Usage
const mediaId = await uploadMedia('./product.jpg', 'image/jpeg');
await sendImageById('628123456789', mediaId, 'Produk baru!');

Kirim Video:

javascript

async function sendVideo(to, videoUrl, caption = '') {
    const payload = {
        messaging_product: 'whatsapp',
        to: to,
        type: 'video',
        video: {
            link: videoUrl,
            caption: caption
        }
    };
    
    return await sendMessage(payload);
}

// Usage
await sendVideo(
    '628123456789',
    'https://brand.com/tutorial.mp4',
    'Tutorial penggunaan produk 📹'
);

Kirim Document:

javascript

async function sendDocument(to, documentUrl, filename, caption = '') {
    const payload = {
        messaging_product: 'whatsapp',
        to: to,
        type: 'document',
        document: {
            link: documentUrl,
            filename: filename,
            caption: caption
        }
    };
    
    return await sendMessage(payload);
}

// Usage
await sendDocument(
    '628123456789',
    'https://brand.com/invoice.pdf',
    'Invoice-ORD123.pdf',
    'Invoice pesanan kamu 📄'
);

Kirim Audio:

javascript

async function sendAudio(to, audioUrl) {
    const payload = {
        messaging_product: 'whatsapp',
        to: to,
        type: 'audio',
        audio: {
            link: audioUrl
        }
    };
    
    return await sendMessage(payload);
}

// Usage - Voice note style
await sendAudio(
    '628123456789',
    'https://brand.com/voicenote.ogg'
);

Kirim Sticker:

javascript

async function sendSticker(to, stickerUrl) {
    const payload = {
        messaging_product: 'whatsapp',
        to: to,
        type: 'sticker',
        sticker: {
            link: stickerUrl // WebP format, 512x512
        }
    };
    
    return await sendMessage(payload);
}

Terima Media

Handle Incoming Media:

javascript

async function handleIncomingMedia(message) {
    const mediaType = message.type; // image, video, audio, document
    const mediaInfo = message[mediaType]; // Get media details
    
    console.log(`Received ${mediaType}:`, mediaInfo);
    
    // mediaInfo contains:
    // - id: Media ID
    // - mime_type: MIME type
    // - sha256: Hash for verification
    // - caption: Caption (for image/video)
    
    // Download the media
    const mediaBuffer = await downloadMedia(mediaInfo.id);
    
    // Save or process
    await saveMedia(mediaBuffer, mediaInfo);
}

Download Media:

javascript

async function downloadMedia(mediaId) {
    // Step 1: Get media URL
    const urlResponse = await axios.get(
        `https://graph.facebook.com/v17.0/${mediaId}`,
        {
            headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}` }
        }
    );
    
    const mediaUrl = urlResponse.data.url;
    
    // Step 2: Download media content
    const mediaResponse = await axios.get(mediaUrl, {
        headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}` },
        responseType: 'arraybuffer'
    });
    
    return Buffer.from(mediaResponse.data);
}

// Save to file
async function saveMedia(buffer, mediaInfo) {
    const extension = getExtension(mediaInfo.mime_type);
    const filename = `${mediaInfo.id}.${extension}`;
    const filepath = `./uploads/${filename}`;
    
    await fs.promises.writeFile(filepath, buffer);
    
    return filepath;
}

function getExtension(mimeType) {
    const map = {
        'image/jpeg': 'jpg',
        'image/png': 'png',
        'video/mp4': 'mp4',
        'audio/ogg': 'ogg',
        'audio/mpeg': 'mp3',
        'application/pdf': 'pdf'
    };
    return map[mimeType] || 'bin';
}

Webhook Handler untuk Media

javascript

app.post('/webhook', async (req, res) => {
    res.status(200).send('OK');
    
    const body = req.body;
    
    for (const entry of body.entry) {
        for (const change of entry.changes) {
            if (change.field === 'messages') {
                const messages = change.value.messages || [];
                
                for (const message of messages) {
                    switch (message.type) {
                        case 'image':
                            await handleImage(message);
                            break;
                        case 'video':
                            await handleVideo(message);
                            break;
                        case 'audio':
                            await handleAudio(message);
                            break;
                        case 'document':
                            await handleDocument(message);
                            break;
                        case 'sticker':
                            await handleSticker(message);
                            break;
                    }
                }
            }
        }
    }
});

async function handleImage(message) {
    const { id, caption, mime_type } = message.image;
    
    console.log(`Image received: ${id}`);
    if (caption) console.log(`Caption: ${caption}`);
    
    // Download dan simpan
    const buffer = await downloadMedia(id);
    const path = await saveMedia(buffer, { id, mime_type });
    
    // Process - misalnya OCR, image recognition
    // await processImage(path);
}

async function handleDocument(message) {
    const { id, filename, mime_type } = message.document;
    
    console.log(`Document received: ${filename}`);
    
    // Download
    const buffer = await downloadMedia(id);
    
    // Simpan dengan nama asli
    const path = `./uploads/${filename}`;
    await fs.promises.writeFile(path, buffer);
    
    // Process - misalnya extract text dari PDF
    // await processDocument(path);
}

Unofficial API (Baileys)

Kirim Media:

javascript

const { default: makeWASocket } = require('@whiskeysockets/baileys');

// Kirim image
async function sendImage(sock, to, imagePath, caption) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        image: { url: imagePath }, // atau fs.readFileSync(imagePath)
        caption: caption
    });
}

// Kirim video
async function sendVideo(sock, to, videoPath, caption) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        video: { url: videoPath },
        caption: caption,
        gifPlayback: false // true untuk GIF
    });
}

// Kirim document
async function sendDocument(sock, to, docPath, filename) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        document: { url: docPath },
        fileName: filename,
        mimetype: 'application/pdf'
    });
}

// Kirim audio sebagai voice note
async function sendVoiceNote(sock, to, audioPath) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        audio: { url: audioPath },
        ptt: true // push to talk = voice note
    });
}

Terima Media:

javascript

sock.ev.on('messages.upsert', async ({ messages }) => {
    for (const msg of messages) {
        if (msg.message?.imageMessage) {
            const buffer = await downloadMediaMessage(
                msg,
                'buffer',
                {},
                { reuploadRequest: sock.updateMediaMessage }
            );
            
            await fs.promises.writeFile('./received.jpg', buffer);
        }
        
        if (msg.message?.documentMessage) {
            const buffer = await downloadMediaMessage(msg, 'buffer', {});
            const filename = msg.message.documentMessage.fileName;
            
            await fs.promises.writeFile(`./uploads/${filename}`, buffer);
        }
    }
});

Best Practices

DO ✅

- Compress sebelum kirim
- Gunakan format yang tepat
- Cache media yang sering dipakai
- Handle download errors
- Validate file sebelum process
- Cleanup temporary files

DON'T ❌

- Kirim file terlalu besar
- Ignore MIME type
- Skip error handling
- Simpan semua tanpa cleanup
- Assume download selalu sukses
- Kirim format tidak didukung

Optimasi Media

javascript

const sharp = require('sharp');

// Compress image sebelum kirim
async function compressImage(inputPath, maxWidth = 1024) {
    const outputPath = inputPath.replace('.jpg', '_compressed.jpg');
    
    await sharp(inputPath)
        .resize(maxWidth, null, { withoutEnlargement: true })
        .jpeg({ quality: 80 })
        .toFile(outputPath);
    
    return outputPath;
}

// Validate file size
function validateFileSize(filePath, maxSizeMB) {
    const stats = fs.statSync(filePath);
    const fileSizeMB = stats.size / (1024 * 1024);
    
    return fileSizeMB <= maxSizeMB;
}

FAQ

Berapa max file size?

Image: 5MB, Video: 16MB, Document: 100MB. Compress jika lebih besar.

Format apa yang paling reliable?

Image: JPEG, Video: MP4 (H.264), Document: PDF. Paling compatible.

Media URL harus public?

Ya untuk Cloud API. URL harus accessible tanpa auth.


Kesimpulan

Media = Engagement lebih tinggi!

Text OnlyDengan Media
Kurang menarikEye-catching
TerbatasRich content
Low engagementHigh engagement

Mulai Kirim Media →


Artikel Terkait