๐ Introduction
Webhook memungkinkan aplikasi Anda menerima notifikasi real-time ketika ada event terjadi di device WhatsApp Anda. Dengan webhook, Anda tidak perlu melakukan polling untuk mengecek pesan baru - kami akan mengirimkan notifikasi langsung ke server Anda.
โจ Keuntungan Menggunakan Webhook:
- Real-time notification - terima pesan instant
- Efisien - tidak perlu polling terus-menerus
- Scalable - bisa handle banyak device sekaligus
- Reliable - otomatis retry jika gagal
๐ก Use Cases:
- Customer service bot - auto-reply berdasarkan keyword
- Order notification - kirim update status pesanan
- CRM integration - sync kontak & chat history
- Analytics - track incoming messages & engagement
โ๏ธ Setup Webhook
Step 1: Buat Endpoint Webhook
Siapkan endpoint di server Anda yang akan menerima POST request dari WAGate:
// PHP Example - webhook-receiver.php
<?php
header('Content-Type: application/json');
// Get POST data
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
// Log received webhook
file_put_contents('webhook.log', date('Y-m-d H:i:s') . ' - ' . $payload . "\n", FILE_APPEND);
// Process based on event type
if ($data['event'] === 'message') {
$from = $data['data']['from'];
$message = $data['data']['message'];
// Your logic here
// Example: Save to database, send auto-reply, etc.
}
// Return success response
echo json_encode(['success' => true]);
?>
Step 2: Konfigurasi di Dashboard
- Login ke Dashboard Webhook
- Pilih device WhatsApp Anda
- Masukkan Webhook URL (contoh:
https://yourapp.com/webhook/whatsapp) - Pilih events yang ingin Anda terima (minimal: message)
- Copy Webhook Secret untuk signature verification
- Klik "Aktifkan Webhook"
- Klik "Test Webhook" untuk verifikasi koneksi
โ ๏ธ Requirements:
- Webhook URL harus menggunakan HTTPS (production)
- Endpoint harus return response dalam 10 detik
- Response HTTP status 200-299 dianggap sukses
- Jika gagal 10x berturut-turut, webhook otomatis dinonaktifkan
๐ฌ Webhook Events
Pilih events yang ingin Anda terima di webhook:
๐จ message
Dikirim ketika device Anda menerima pesan WhatsApp (text, image, video, dll)
Recommendedโ message_ack
Dikirim ketika status pesan berubah (sent โ delivered โ read)
Optional๐ฑ qr
Dikirim ketika QR code baru di-generate (untuk re-connect)
Optionalโ ready
Dikirim ketika device berhasil connect ke WhatsApp
Optionalโ disconnected
Dikirim ketika device terputus dari WhatsApp
Optional๐ฆ Payload Structure
Message Event
{
"event": "message",
"device_id": "wa-user123-1234567890",
"timestamp": "2025-12-16T14:30:00.000Z",
"data": {
"from": "6281234567890",
"message": "Halo, saya mau pesan produk A",
"message_id": "3EB0B430B6F8F1D0E5F2",
"name": "John Doe",
"type": "text",
"timestamp": 1702740600
}
}
Message with Image
{
"event": "message",
"device_id": "wa-user123-1234567890",
"timestamp": "2025-12-16T14:35:00.000Z",
"data": {
"from": "6281234567890",
"message": "Lihat foto ini",
"message_id": "3EB0B430B6F8F1D0E5F3",
"name": "John Doe",
"type": "image",
"timestamp": 1702740900,
"media": {
"mimetype": "image/jpeg",
"data": "base64_encoded_image_data...",
"filename": "photo.jpg"
}
}
}
Ready Event
{
"event": "ready",
"device_id": "wa-user123-1234567890",
"timestamp": "2025-12-16T14:20:00.000Z",
"data": {
"phone_number": "6285161058860",
"device_name": "My WhatsApp Bot"
}
}
Field Descriptions
| Field | Type | Description |
|---|---|---|
| event | string | Event type (message, ready, disconnected, dll) |
| device_id | string | ID unik device WhatsApp Anda |
| timestamp | string | Waktu event (ISO 8601 format) |
| data.from | string | Nomor pengirim (format: 62xxx) |
| data.message | string | Isi pesan |
| data.message_id | string | ID unik pesan WhatsApp |
| data.name | string | Nama kontak pengirim |
| data.type | string | Tipe pesan (text, image, video, audio, document) |
๐ Signature Verification
Setiap webhook request dilengkapi dengan signature di header X-Webhook-Signature
untuk memastikan request berasal dari WAGate.
Headers Yang Dikirim
POST /webhook/whatsapp HTTP/1.1
Host: yourapp.com
Content-Type: application/json
X-Webhook-Signature: a3f5b8c9d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7
X-Device-Id: wa-user123-1234567890
Cara Verifikasi (PHP)
$payload = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$webhookSecret = 'your_webhook_secret_from_dashboard';
// Hitung signature
$expectedSignature = hash_hmac('sha256', $payload, $webhookSecret);
// Verifikasi
if (hash_equals($expectedSignature, $receivedSignature)) {
// โ
Valid webhook dari WAGate
$data = json_decode($payload, true);
// Process webhook...
} else {
// โ Invalid signature - reject request
http_response_code(401);
die('Unauthorized');
}
Cara Verifikasi (Node.js)
const crypto = require('crypto');
const express = require('express');
const app = express();
app.post('/webhook/whatsapp', express.json(), (req, res) => {
const receivedSignature = req.headers['x-webhook-signature'];
const webhookSecret = 'your_webhook_secret_from_dashboard';
// Hitung signature
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(JSON.stringify(req.body))
.digest('hex');
// Verifikasi
if (expectedSignature === receivedSignature) {
// โ
Valid webhook
const { event, data } = req.body;
if (event === 'message') {
console.log('New message from:', data.from);
console.log('Message:', data.message);
}
res.json({ success: true });
} else {
// โ Invalid signature
res.status(401).json({ error: 'Unauthorized' });
}
});
โ ๏ธ Security Best Practices:
- Selalu verifikasi signature sebelum memproses webhook
- Simpan webhook secret di environment variable, jangan hardcode
- Gunakan HTTPS untuk webhook URL (production)
- Gunakan
hash_equals()untuk mencegah timing attacks
๐ป Complete Examples
Laravel Example
// routes/api.php
Route::post('/webhook/whatsapp', [WebhookController::class, 'handle']);
// app/Http/Controllers/WebhookController.php
public function handle(Request $request)
{
// Verify signature
$payload = $request->getContent();
$signature = $request->header('X-Webhook-Signature');
$secret = config('services.wagate.webhook_secret');
$expected = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected, $signature)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
// Process webhook
$event = $request->input('event');
$data = $request->input('data');
if ($event === 'message') {
// Auto-reply example
if (stripos($data['message'], 'harga') !== false) {
$this->sendReply($data['from'], 'Harga produk kami mulai dari Rp 50.000');
}
// Save to database
Message::create([
'from' => $data['from'],
'message' => $data['message'],
'received_at' => now(),
]);
}
return response()->json(['success' => true]);
}
private function sendReply($to, $message)
{
// Call WAGate API to send message
Http::withToken(config('services.wagate.api_token'))
->post('https://wagate.in/api/webhook/send/your-session-id', [
'to' => $to,
'message' => $message,
]);
}
Python Example (Flask)
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
app = Flask(__name__)
WEBHOOK_SECRET = 'your_webhook_secret'
@app.route('/webhook/whatsapp', methods=['POST'])
def webhook():
# Get signature
signature = request.headers.get('X-Webhook-Signature', '')
# Calculate expected signature
payload = request.get_data()
expected = hmac.new(
WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()
# Verify
if not hmac.compare_digest(expected, signature):
return jsonify({'error': 'Unauthorized'}), 401
# Process webhook
data = request.get_json()
if data['event'] == 'message':
from_number = data['data']['from']
message = data['data']['message']
print(f"New message from {from_number}: {message}")
# Your logic here
if 'help' in message.lower():
send_reply(from_number, 'Silakan hubungi admin di 08123456789')
return jsonify({'success': True})
def send_reply(to, message):
import requests
response = requests.post(
'https://wagate.in/api/webhook/send/your-session-id',
headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
json={'to': to, 'message': message}
)
return response.json()
if __name__ == '__main__':
app.run(port=5000)
Auto-Reply Bot Example
// Simple auto-reply bot
app.post('/webhook/whatsapp', (req, res) => {
const { event, data } = req.body;
if (event === 'message') {
const message = data.message.toLowerCase();
const from = data.from;
// Keyword-based auto-reply
const replies = {
'halo': 'Halo! Ada yang bisa kami bantu?',
'harga': 'Harga produk kami mulai dari Rp 50.000. Silakan cek katalog lengkap di website kami.',
'order': 'Untuk order silakan ketik: ORDER [Nama Produk] [Jumlah]',
'cs': 'Customer Service kami siap membantu di 08123456789',
'jam': `Kami buka Senin-Jumat 09:00-17:00 WIB`,
};
// Check keywords
for (const [keyword, reply] of Object.entries(replies)) {
if (message.includes(keyword)) {
sendMessage(from, reply);
break;
}
}
// Save to database
saveMessage(data);
}
res.json({ success: true });
});
๐งช Testing Webhook
1. Test di Dashboard
Cara termudah untuk test webhook:
- Login ke Dashboard Webhook
- Pilih device Anda
- Klik tombol "๐งช Test Webhook"
- Cek log di server Anda - seharusnya menerima test payload
2. Gunakan Webhook.site
Untuk testing tanpa server:
- Buka webhook.site
- Copy URL unik yang diberikan (contoh:
https://webhook.site/xxx-xxx-xxx) - Paste URL tersebut ke Dashboard โ Webhook URL
- Aktifkan webhook dan test - lihat payload di webhook.site
3. Local Testing dengan ngrok
Untuk test di localhost:
# Install ngrok
# Download dari https://ngrok.com/download
# Jalankan local server Anda (contoh: port 8000)
php artisan serve
# Di terminal lain, jalankan ngrok
ngrok http 8000
# Copy URL yang muncul (contoh: https://abc123.ngrok.io)
# Paste ke Dashboard Webhook URL: https://abc123.ngrok.io/webhook/whatsapp
# Kirim test webhook dari dashboard
# Cek terminal ngrok - Anda akan lihat request masuk!
๐ก Tips Testing:
- Gunakan webhook.site untuk melihat raw payload
- Gunakan ngrok untuk test di localhost
- Check webhook logs di Dashboard untuk debug
- Lihat response status & response time di log
๐ง Troubleshooting
โ Webhook tidak diterima
Cek:
- Webhook enabled di dashboard?
- URL webhook benar? (harus HTTPS untuk production)
- Server dapat diakses dari internet? (test dengan curl)
- Event "message" sudah dipilih?
- Firewall tidak blokir request dari WAGate?
โ ๏ธ Webhook disabled otomatis
Penyebab:
- Endpoint return error (status 4xx/5xx) 10x berturut-turut
- Endpoint timeout (> 10 detik) berulang kali
Solusi:
- Fix endpoint Anda (cek error log)
- Pastikan response < 10 detik
- Aktifkan kembali webhook di dashboard
๐ Response lambat
Best Practice:
- Return response
200 OKsegera setelah validasi - Process webhook di background (queue/job)
- Jangan panggil API external di webhook handler (kecuali quick response)
- Target: response < 1 detik
๐ Debug Mode
Cara debug:
// Log semua webhook untuk debugging
file_put_contents('webhook-debug.log',
date('Y-m-d H:i:s') . "\n" .
"Headers: " . json_encode(getallheaders()) . "\n" .
"Body: " . file_get_contents('php://input') . "\n\n",
FILE_APPEND
);
๐ฐ Quota & Billing
๐ Cara Hitung Quota
Setiap pesan (masuk & keluar) mengurangi quota Anda:
๐ค Pesan Keluar (API)
Anda kirim pesan via API:
POST /api/webhook/send
-1 quota
๐ฅ Pesan Masuk (Webhook)
Customer kirim pesan ke Anda:
Webhook โ Your Server
-1 quota
๐ Contoh:
- Customer kirim "Halo" โ -1 quota
- Anda reply via API "Halo juga" โ -1 quota
- Total: -2 quota
๐ Cek Quota
Lihat quota Anda di Dashboard atau via API:
GET https://wagate.in/api/webhook/quota
Authorization: Bearer YOUR_API_TOKEN
# Response:
{
"success": true,
"data": {
"quota_limit": 1000,
"quota_used": 234,
"quota_remaining": 766,
"quota_sent": 120,
"quota_received": 114,
"quota_reset_at": "2025-01-01T00:00:00Z"
}
}
โ ๏ธ Quota Habis?
Jika quota habis:
- โ Webhook masih diterima (pesan masuk masuk log)
- โ API send message di-blokir (return 429 error)
- โ Webhook tidak dikirim ke server Anda
Solusi: Upgrade plan atau tunggu reset quota bulan depan
๐ค Butuh Bantuan?
Tim support kami siap membantu Anda!