WhatsApp API Media Handling
Panduan lengkap kirim dan terima media via WhatsApp API. Gambar, video, dokumen, audio. Upload, download, best practices!
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 pixelsKirim 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 filesDON'T ❌
- Kirim file terlalu besar
- Ignore MIME type
- Skip error handling
- Simpan semua tanpa cleanup
- Assume download selalu sukses
- Kirim format tidak didukungOptimasi 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 Only | Dengan Media |
|---|---|
| Kurang menarik | Eye-catching |
| Terbatas | Rich content |
| Low engagement | High engagement |