Langsung ke konten utama

Webhook

Webhook memungkinkan Anda menerima callback HTTP secara real-time saat event terjadi pada instance WhatsApp Anda. Daripada polling API, Wappfy mendorong event ke server Anda saat terjadi.

Event yang Didukung

Wappfy mendukung 12 jenis event webhook:
EventDeskripsi
message.receivedPesan masuk baru telah diterima.
message.sentPesan keluar berhasil dikirim.
message.deliveredPesan terkirim telah diterima oleh perangkat penerima (tanda centang ganda).
message.readPesan terkirim telah dibaca oleh penerima (tanda centang biru).
message.failedPesan keluar gagal dikirim.
message.reactionSeseorang bereaksi terhadap pesan dengan emoji.
EventDeskripsi
instance.connectedInstance berhasil terhubung ke WhatsApp.
instance.disconnectedInstance kehilangan koneksi WhatsApp.
instance.qrKode QR baru tersedia untuk dipindai.
EventDeskripsi
group.joinedPeserta bergabung ke grup (termasuk bot itu sendiri).
group.leftPeserta meninggalkan grup.
contact.createdKontak baru disimpan atau terdeteksi.

Membuat Webhook

Daftarkan endpoint webhook untuk mulai menerima event.
curl -X POST https://api.wappfy.io/api/webhooks \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/wappfy",
    "events": ["message.received", "message.sent", "message.delivered"],
    "instance_id": "inst_abc123",
    "secret": "whsec_my_signing_secret",
    "retry_count": 3,
    "timeout_ms": 10000
  }'
Respons:
{
  "data": {
    "id": "wh_xyz789",
    "url": "https://your-server.com/webhooks/wappfy",
    "events": ["message.received", "message.sent", "message.delivered"],
    "instance_id": "inst_abc123",
    "is_active": true,
    "retry_count": 3,
    "timeout_ms": 10000,
    "created_at": "2026-02-10T12:00:00Z"
  }
}

Opsi Konfigurasi

FieldTipeDefaultDeskripsi
urlstringwajibURL HTTPS yang akan menerima permintaan POST webhook.
eventsstring[]wajibArray jenis event yang ingin di-subscribe.
instance_idstringnullBatasi webhook ke instance tertentu. Jika null, menerima event dari semua instance.
secretstringnullSecret yang digunakan untuk menghasilkan tanda tangan HMAC untuk verifikasi payload.
retry_countnumber3Jumlah percobaan ulang jika pengiriman gagal (0-5).
timeout_msnumber10000Timeout permintaan dalam milidetik (1000-30000).
Field instance_id bersifat opsional. Jika tidak diisi, webhook akan menerima event dari semua instance di akun Anda.

Melihat Daftar Webhook

curl https://api.wappfy.io/api/webhooks \
  -H "X-Api-Key: YOUR_API_KEY"
Respons:
{
  "data": [
    {
      "id": "wh_xyz789",
      "url": "https://your-server.com/webhooks/wappfy",
      "events": ["message.received", "message.sent", "message.delivered"],
      "instance_id": "inst_abc123",
      "is_active": true,
      "retry_count": 3,
      "timeout_ms": 10000
    }
  ]
}

Memperbarui Webhook

Perbarui URL, event, atau konfigurasi webhook yang sudah ada.
curl -X PATCH https://api.wappfy.io/api/webhooks/wh_xyz789 \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["message.received", "message.sent", "message.delivered", "message.read"],
    "is_active": true
  }'

Menghapus Webhook

curl -X DELETE https://api.wappfy.io/api/webhooks/wh_xyz789 \
  -H "X-Api-Key: YOUR_API_KEY"

Format Payload Pengiriman

Saat event terjadi, Wappfy mengirim permintaan POST ke URL webhook Anda dengan struktur berikut:
{
  "id": "dlv_abc123def456",
  "event": "message.received",
  "instance_id": "inst_abc123",
  "timestamp": "2026-02-10T14:30:00Z",
  "data": {
    "message_id": "BAE5F2C4D3B2A1",
    "chat_id": "[email protected]",
    "from": "[email protected]",
    "type": "text",
    "text": "Hello!",
    "timestamp": "2026-02-10T14:30:00Z"
  }
}

Field Payload

FieldDeskripsi
idID pengiriman unik. Gunakan ini untuk deduplikasi.
eventJenis event yang memicu pengiriman ini.
instance_idInstance yang menghasilkan event.
timestampTimestamp ISO 8601 kapan event terjadi.
dataPayload spesifik event. Konten bervariasi berdasarkan jenis event.

Verifikasi Tanda Tangan HMAC

Jika Anda menyediakan secret saat membuat webhook, setiap pengiriman akan menyertakan header X-Wappfy-Signature yang berisi tanda tangan HMAC-SHA256 dari body permintaan. Selalu verifikasi tanda tangan ini untuk memastikan permintaan berasal dari Wappfy dan tidak diubah.

Contoh Verifikasi

const crypto = require("crypto");

function verifyWebhookSignature(req, secret) {
  const signature = req.headers["x-wappfy-signature"];
  if (!signature) return false;

  const expectedSignature = crypto
    .createHmac("sha256", secret)
    .update(JSON.stringify(req.body))
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express middleware
app.post("/webhooks/wappfy", (req, res) => {
  const isValid = verifyWebhookSignature(req, "whsec_my_signing_secret");

  if (!isValid) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const { event, data } = req.body;
  console.log(`Received event: ${event}`, data);

  // Always respond with 200 quickly to prevent retries
  res.status(200).json({ received: true });
});
Selalu gunakan perbandingan waktu konstan (seperti timingSafeEqual atau hmac.compare_digest) saat memverifikasi tanda tangan untuk mencegah serangan timing.

Perilaku Percobaan Ulang

Jika server Anda tidak merespons dengan kode status 2xx dalam waktu timeout_ms yang dikonfigurasi, Wappfy akan mencoba ulang pengiriman.
PercobaanJeda
Percobaan ulang ke-110 detik
Percobaan ulang ke-260 detik
Percobaan ulang ke-35 menit
Percobaan ulang ke-430 menit
Percobaan ulang ke-52 jam
Percobaan ulang berhenti saat respons 2xx diterima atau retry_count habis. Jumlah percobaan ulang default adalah 3.

Melihat Riwayat Pengiriman

Periksa log pengiriman untuk webhook guna melihat percobaan pengiriman sebelumnya dan hasilnya.
curl https://api.wappfy.io/api/webhooks/wh_xyz789/deliveries \
  -H "X-Api-Key: YOUR_API_KEY"
Respons:
{
  "data": [
    {
      "id": "dlv_abc123def456",
      "event": "message.received",
      "status": "delivered",
      "http_status": 200,
      "attempts": 1,
      "created_at": "2026-02-10T14:30:00Z",
      "delivered_at": "2026-02-10T14:30:01Z"
    },
    {
      "id": "dlv_ghi789jkl012",
      "event": "message.sent",
      "status": "failed",
      "http_status": 500,
      "attempts": 3,
      "created_at": "2026-02-10T14:31:00Z",
      "last_error": "Server returned 500 Internal Server Error"
    }
  ]
}

Contoh Payload Event

{
  "id": "dlv_abc123",
  "event": "message.received",
  "instance_id": "inst_abc123",
  "timestamp": "2026-02-10T14:30:00Z",
  "data": {
    "message_id": "BAE5F2C4D3B2A1",
    "chat_id": "[email protected]",
    "from": "[email protected]",
    "type": "text",
    "text": "Hello, I need help with my order",
    "timestamp": "2026-02-10T14:30:00Z"
  }
}
{
  "id": "dlv_def456",
  "event": "message.delivered",
  "instance_id": "inst_abc123",
  "timestamp": "2026-02-10T14:30:05Z",
  "data": {
    "message_id": "BAE5A1B2C3D4E5",
    "chat_id": "[email protected]",
    "status": "delivered"
  }
}
{
  "id": "dlv_ghi789",
  "event": "message.read",
  "instance_id": "inst_abc123",
  "timestamp": "2026-02-10T14:31:00Z",
  "data": {
    "message_id": "BAE5A1B2C3D4E5",
    "chat_id": "[email protected]",
    "status": "read"
  }
}
{
  "id": "dlv_jkl012",
  "event": "message.reaction",
  "instance_id": "inst_abc123",
  "timestamp": "2026-02-10T14:32:00Z",
  "data": {
    "message_id": "BAE5F2C4D3B2A1",
    "chat_id": "[email protected]",
    "from": "[email protected]",
    "reaction": "\u2764\ufe0f"
  }
}
{
  "id": "dlv_mno345",
  "event": "instance.connected",
  "instance_id": "inst_abc123",
  "timestamp": "2026-02-10T12:00:00Z",
  "data": {
    "instance_id": "inst_abc123",
    "status": "connected",
    "phone_number": "5511999998888"
  }
}
{
  "id": "dlv_pqr678",
  "event": "instance.qr",
  "instance_id": "inst_abc123",
  "timestamp": "2026-02-10T11:59:00Z",
  "data": {
    "instance_id": "inst_abc123",
    "qr": "data:image/png;base64,iVBORw0KGgo..."
  }
}
{
  "id": "dlv_stu901",
  "event": "group.joined",
  "instance_id": "inst_abc123",
  "timestamp": "2026-02-10T15:00:00Z",
  "data": {
    "group_id": "[email protected]",
    "participant": "[email protected]"
  }
}

Praktik Terbaik

Respons dengan cepat

Kembalikan status 200 dalam waktu 5 detik. Proses event secara asinkron untuk menghindari timeout.

Deduplikasi

Gunakan id pengiriman untuk mendeteksi dan melewati pengiriman duplikat yang disebabkan oleh percobaan ulang.

Verifikasi tanda tangan

Selalu validasi header X-Wappfy-Signature jika Anda mengonfigurasi secret.

Gunakan HTTPS

URL webhook harus menggunakan HTTPS. Endpoint HTTP akan ditolak.