Skip to content

Tangani balasan interaktif

Cara parsing quick-reply dan pilihan list yang dikirim user WhatsApp.

Updated View as Markdown

Pas user tap pesan tombol atau menu list yang kamu kirim, Wazapin bakal trigger webhook.

Ikuti panduan ini buat kenali balasan interaktif dan ambil pilihan yang user klik.

Kapan kamu butuh ini

Balasan interaktif kepakai buat:

  • Arahkan pelanggan ke alur yang beda (mis. Sales vs Support).
  • Konfirmasi aksi transaksi (mis. tap “Konfirmasi Pesanan” atau “Jadwal Ulang”).
  • Bikin menu chatbot otomatis dan navigator FAQ.

Alur proses

Handle pilihan interaktif cuma butuh tiga langkah:

graph TD
    A[User tap tombol atau item list] --> B[Webhook message.new msg_type: interactive]
    B --> C[GET /v1/messages/{id} buat ambil detail]
    C --> D{interactive.type?}
    D -->|button_reply| E[Baca ID & title tombol]
    D -->|list_reply| F[Baca row ID, title & description]

1. Terima webhook interaktif

Wazapin kirim webhook message.new yang ringan dengan msg_type: "interactive".

Contoh payload webhook-nya:

{
  "message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "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": "interactive"
}

2. Ambil detail pilihannya

Panggil GET /v1/messages/{messageID} pakai message_id dari payload. Di response bakal ada object interactive di dalam blok content yang jelasin input user.


Struktur interaktif

Tergantung tipe pesannya, detail yang balik punya dua bentuk:

Tombol quick-reply (button_reply)

Kalau user tap tombol, blok interactive bakal punya type "button_reply":

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "type": "interactive",
  "content": {
    "interactive": {
      "type": "button_reply",
      "button_reply": {
        "id": "confirm_yes",
        "title": "Yes, I confirm"
      }
    }
  }
}

Baris menu list (list_reply)

Kalau user pilih opsi dari menu list, blok interactive bakal punya type "list_reply":

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "type": "interactive",
  "content": {
    "interactive": {
      "type": "list_reply",
      "list_reply": {
        "id": "support_agent",
        "title": "Talk to Support",
        "description": "Connect to a live agent"
      }
    }
  }
}

Contoh kode

Cara handle webhook dan proses pilihan user:

# Ambil detail pesan buat cek pilihan user
curl -X GET "https://api.wazapin.com/v1/messages/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -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 {
    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"));

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

    // 1. Ambil pilihan interaktif
    const { data: message } = await wazapin.messages.get(messageId);
    const interactive = message.content?.interactive;

    if (interactive) {
      if (interactive.type === "button_reply") {
        const button = interactive.button_reply;
        console.log(`User tap tombol ID: ${button.id} label: ${button.title}`);
        // Arahkan pelanggan ke flow yang sesuai
      } else if (interactive.type === "list_reply") {
        const row = interactive.list_reply;
        console.log(`User pilih opsi list ID: ${row.id} label: ${row.title}`);
        // Handle pilihan list
      }
    }
  }

  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()

    if payload.get("direction") == "inbound" and payload.get("msg_type") == "interactive":
        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", {})
            interactive = message_data.get("content", {}).get("interactive", {})
            interactive_type = interactive.get("type")
            
            if interactive_type == "button_reply":
                button = interactive.get("button_reply", {})
                print(f"User tap tombol: {button.get('id')} ({button.get('title')})")
            elif interactive_type == "list_reply":
                row = interactive.get("list_reply", {})
                print(f"User pilih opsi: {row.get('id')} ({row.get('title')})")

    return {"ok": True}

Troubleshooting

Webhook masuk tapi interactive kosong

Pastiin kamu ambil pesan pakai ID lewat GET /v1/messages/{messageID}. Body webhook memang sengaja dibikin ringkas dan nggak bawa blok interactive langsung.

User pencet banyak tombol

WhatsApp nggak bolehin pilih banyak opsi di satu pesan. Tiap tap itu atomic dan masuk sebagai webhook terpisah. Kalau user coba tap tombol di pesan lama, sistem kamu bakal dapat webhook baru dengan message_id yang beda. Kamu bisa lacak pesan aslinya lewat timeline conversation atau header parent message kalau ada.


Navigation

Type to search…

↑↓ navigate↵ selectEsc close