Skip to content

Tangani media masuk dari webhook

Cara deteksi, ambil, dan download foto, video, dokumen, serta stiker yang dikirim user WhatsApp.

Updated View as Markdown

Begitu user WhatsApp kirim gambar, video, voice note, dokumen, atau stiker ke nomor kamu, Wazapin langsung kasih tahu server kamu lewat webhook.

Ikuti panduan ini buat kenali pesan media, ambil URL download-nya, dan simpan file-nya ke server atau cloud storage kamu.

Kapan kamu butuh ini

Handle media masuk penting buat:

  • Simpan PDF, struk, atau invoice yang di-upload pelanggan.
  • Proses foto atau video dari user buat keperluan support.
  • Arsipkan voice note (pesan audio) buat transkripsi atau QA.

Alur proses

Download media dari user butuh tiga langkah:

graph TD
    A[User kirim gambar/dokumen] --> B[Webhook message.new msg_type: image/document]
    B --> C[GET /v1/messages/{id} buat ambil media_url]
    C --> D[Fetch dan stream file media ke storage]
    D --> E[Balas webhook 200 OK]

1. Deteksi webhook media

Wazapin kirim webhook message.new yang ringan dengan msg_type berisi image, video, audio, document, atau sticker.

Contoh payload webhook buat gambar masuk:

{
  "message_id": "9f1fd66d-c37a-4b50-a8c2-b4dca523f9c8",
  "conversation_id": "0f89b0f9-74b4-44f9-b9b6-48f6d4de57aa",
  "contact_id": "c1a2b3c4-d5e6-7890-abcd-ef1234567890",
  "channel_id": "wzp_abc123",
  "direction": "inbound",
  "from_phone": "6281234567890",
  "msg_type": "image"
}

2. Ambil URL media

Panggil GET /v1/messages/{messageID} pakai message_id dari payload. Di response API bakal ada blok content dengan link download langsung:

  • Buat gambar/video/audio/dokumen: content.media_url
  • Buat stiker: content.sticker_url

3. Download file-nya

Stream konten biner dari media_url (atau sticker_url) ke file system lokal, AWS S3, Google Cloud Storage, atau storage lain yang kamu pakai.


Contoh kode

Cara tangkap webhook, ambil detail pesan, dan download file-nya:

# 1. Ambil detail pesan buat dapat media_url
curl -X GET "https://api.wazapin.com/v1/messages/9f1fd66d-c37a-4b50-a8c2-b4dca523f9c8" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Accept: application/json"

# 2. Download file biner langsung pakai media_url dari response
curl -o "receipt.png" "https://api.wazapin.com/v1/media/assets/download_url"
import express from "express";
import { Webhook } from "svix";
import { WazapinClient } from "@wazapin/sdk";
import fs from "fs";
import axios from "axios";
import path from "path";

const app = express();
const wazapin = new WazapinClient({ apiKey: process.env.WAZAPIN_API_KEY });
const wh = new Webhook(process.env.WAZAPIN_WEBHOOK_SECRET!);

app.post("/webhooks/wazapin", express.raw({ type: "application/json" }), async (req, res) => {
  try {
    wh.verify(req.body, req.headers as Record<string, string>);
  } catch (err) {
    return res.status(403).send("Invalid signature");
  }

  const payload = JSON.parse(req.body.toString("utf8"));
  const mediaTypes = ["image", "video", "audio", "document", "sticker"];

  if (payload.direction === "inbound" && mediaTypes.includes(payload.msg_type)) {
    const messageId = payload.message_id;

    // 1. Ambil data pesan buat dapat URL media
    const { data: message } = await wazapin.messages.get(messageId);
    
    // Stiker pakai content.sticker_url; tipe lain pakai content.media_url
    const mediaUrl = message.type === "sticker" 
      ? message.content?.sticker_url 
      : message.content?.media_url;

    if (mediaUrl) {
      // 2. Download dan simpan file
      const downloadPath = path.join(__dirname, "downloads", `${messageId}.bin`);
      const response = await axios({
        url: mediaUrl,
        method: "GET",
        responseType: "stream",
      });

      const writer = fs.createWriteStream(downloadPath);
      response.data.pipe(writer);

      writer.on("finish", () => console.log(`Downloaded media to ${downloadPath}`));
      writer.on("error", (err) => console.error("Download failed", err));
    }
  }

  res.status(200).send("OK");
});
from fastapi import FastAPI, Request, HTTPException
from svix.webhooks import Webhook, WebhookVerificationError
import requests
import os

app = FastAPI()
wh = Webhook(os.environ["WAZAPIN_WEBHOOK_SECRET"])
API_KEY = os.environ["WAZAPIN_API_KEY"]

@app.post("/webhooks/wazapin")
async def handle_webhook(request: Request):
    body = await request.body()
    try:
        wh.verify(body, dict(request.headers))
    except WebhookVerificationError:
        raise HTTPException(status_code=403, detail="Invalid signature")

    payload = await request.json()
    media_types = {"image", "video", "audio", "document", "sticker"}

    if payload.get("direction") == "inbound" and payload.get("msg_type") in media_types:
        message_id = payload.get("message_id")
        
        # 1. Ambil detail pesan
        response = requests.get(
            f"https://api.wazapin.com/v1/messages/{message_id}",
            headers={"X-Api-Key": API_KEY, "Accept": "application/json"}
        )
        
        if response.status_code == 200:
            message_data = response.json().get("data", {})
            msg_type = message_data.get("type")
            content = message_data.get("content", {})
            
            # Stiker pakai sticker_url; tipe lain pakai media_url
            media_url = content.get("sticker_url") if msg_type == "sticker" else content.get("media_url")
            
            if media_url:
                # 2. Download dan simpan file
                media_res = requests.get(media_url, stream=True)
                if media_res.status_code == 200:
                    file_path = f"downloads/{message_id}.bin"
                    with open(file_path, "wb") as f:
                        for chunk in media_res.iter_content(chunk_size=8192):
                            f.write(chunk)
                    print(f"Media successfully saved to {file_path}")

    return {"ok": True}

Dukungan channel

Official dan unofficial dua-duanya support pesan media masuk.

  • Channel official: Lewat media server Meta yang aman. URL download-nya berupa proxy link dari Wazapin dengan token yang bakal kedaluwarsa.
  • Channel unofficial: Pairing dengan WhatsApp Web buat cache dan upload aset media ke cloud storage Wazapin.

Detail ukuran media dan MIME type yang didukung, lihat Matriks dukungan channel.


Troubleshooting

URL media kedaluwarsa

URL download media Wazapin pakai token sementara. Biar link nggak keburu mati, langsung download file-nya begitu webhook masuk. Jangan simpan media_url di database dan harap link-nya awet selamanya.

Content-type atau ekstensi salah

Endpoint proxy Wazapin coba tebak MIME type dan ekstensi yang benar. Tapi tetap validasi magic bytes atau header Content-Type pas nulis file ke disk (mis. pastiin file .png beneran punya header PNG) biar nggak ada celah eksekusi.

File yang kedownload malah HTML

Kalau file yang kamu download isinya teks mirip halaman error HTML, cek apakah URL-nya sudah kedaluwarsa atau API key kamu nggak punya izin buat ambil pesan tersebut.


Langkah selanjutnya

Navigation

Type to search…

↑↓ navigate↵ selectEsc close