Tiap customer nge-chat nomor WhatsApp kamu, Wazapin bakal ngirim webhook ke endpoint yang udah kamu set.
Ikutin guide ini buat verifikasi webhook-nya, cek tipe pesannya, dan tarik isi teks lengkapnya lewat API Wazapin.
Prasyarat
Sebelum mulai, siapin dulu:
- Channel WhatsApp udah connect dan endpoint webhook HTTPS udah jadi. Lihat Ikhtisar webhook.
- Webhook kamu udah subscribe ke event
message.new. - Endpoint Signing Secret (misal
whsec_abc123...) dan API Key kamu udah siap.
Alur prosesnya
Handle pesan masuk itu cuma tiga langkah utama:
graph TD
A[Wazapin kirim message.new] --> B[Verifikasi signature & svix-id]
B --> C{msg_type == 'text'?}
C -->|Ya| D[GET /v1/messages/{id} buat ambil konten]
C -->|Tidak| E[Arahin ke handler lain]
D --> F[Proses teks & bales]1. Verifikasi signature
Biar endpoint kamu aman, cek header signature (svix-signature, svix-timestamp, svix-id) pakai signing secret kamu. Butuh helper library? Lihat Verifikasi signature webhook.
2. Parse payload
Pastiin pesannya itu inbound (direction: "inbound") dan tipenya teks (msg_type: "text").
Ini contoh payload JSON buat event teks 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": "text"
}3. Tarik isi pesannya
Webhook inbound itu notifikasi ringan — nggak langsung bawa body teksnya. Pakai message_id dari payload buat hit endpoint GET /v1/messages/{messageID} dan ambil isi teksnya.
Contoh kode
Gini cara handle webhook dan ngambil body pesannya:
# Tarik data pesan pakai message_id dari payload webhook
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"import express from "express";
import { Webhook } from "svix";
import { WazapinClient } from "@wazapin/sdk";
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 {
// 1. Verifikasi signature pakai raw body
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"));
// 2. Filter cuma buat pesan teks masuk
if (payload.direction === "inbound" && payload.msg_type === "text") {
const messageId = payload.message_id;
// 3. Tarik konten lengkapnya
const { data: message } = await wazapin.messages.get(messageId);
// Body teks masuk ada di message.content.text.body
const textContent = message.content?.text?.body;
console.log(`Dapat teks dari ${payload.from_phone}: ${textContent}`);
// Proses pesannya async di sini...
}
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:
# 1. Verifikasi signature
wh.verify(body, dict(request.headers))
except WebhookVerificationError:
raise HTTPException(status_code=403, detail="Invalid signature")
payload = await request.json()
# 2. Filter cuma buat pesan teks masuk
if payload.get("direction") == "inbound" and payload.get("msg_type") == "text":
message_id = payload.get("message_id")
# 3. Tarik konten lengkapnya
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", {})
text_content = message_data.get("content", {}).get("text", {}).get("body")
print(f"Dapat teks dari {payload.get('from_phone')}: {text_content}")
# Proses pesannya async di sini...
return {"ok": True}Troubleshooting
Kok body pesan nggak ada di webhook?
Wajar — Wazapin sengaja bikin webhook-nya ringan biar payload kecil dan latensi rendah. Kamu emang harus hit GET /v1/messages/{messageID} lagi buat baca body teksnya.
Pesan kekirim dobel
Wazapin pakai at-least-once delivery buat webhook. Kalau server kamu slow respon (lebih dari 3 detik) atau bales status non-2xx, Wazapin bakal retry ngirim event-nya. Jadi selalu bales 200 OK secepatnya, terus proses body-nya secara async.
from_phone nggak ada
Field from_phone pasti keisi format internasional (misal 6281234567890) buat pesan inbound. Kalau kamu dapet event tanpa from_phone, cek dulu direction-nya — jangan-jangan itu outbound (echo status pesan terkirim).