๐Ÿ“ก Webhook Documentation

Terima notifikasi real-time dari WhatsApp langsung ke server Anda

๐Ÿ“– 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

  1. Login ke Dashboard Webhook
  2. Pilih device WhatsApp Anda
  3. Masukkan Webhook URL (contoh: https://yourapp.com/webhook/whatsapp)
  4. Pilih events yang ingin Anda terima (minimal: message)
  5. Copy Webhook Secret untuk signature verification
  6. Klik "Aktifkan Webhook"
  7. 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:

  1. Login ke Dashboard Webhook
  2. Pilih device Anda
  3. Klik tombol "๐Ÿงช Test Webhook"
  4. Cek log di server Anda - seharusnya menerima test payload

2. Gunakan Webhook.site

Untuk testing tanpa server:

  1. Buka webhook.site
  2. Copy URL unik yang diberikan (contoh: https://webhook.site/xxx-xxx-xxx)
  3. Paste URL tersebut ke Dashboard โ†’ Webhook URL
  4. 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 OK segera 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!