HILFEZENTRUM

Webhooks

Erhalte automatische HTTP-Benachrichtigungen auf deinem Server, wenn wichtige Ereignisse in WAzion auftreten.

1. Einführung

Webhooks ermöglichen es deinem Server, automatische Benachrichtigungen zu erhalten, wenn bestimmte Ereignisse in WAzion stattfinden. Anstatt regelmäßig nach Neuigkeiten zu fragen, sendet WAzion eine HTTP-POST-Anfrage an deinen Server, wenn etwas Relevantes geschieht.

Wie funktioniert das?

  1. 1 Du konfigurierst eine URL deines Servers im WAzion-Dashboard.
  2. 2 Du wählst aus, welche Veranstaltungen du erhalten möchtest
  3. 3 Wenn ein Ereignis eintritt, sendet WAzion einen POST an deine URL
  4. 4 Ihr Server verarbeitet das Ereignis und antwortet mit HTTP 200

Anwendungsfälle

  • Neue Kontakte mit deinem CRM synchronisieren
  • Leads automatisch erstellen
  • Automatisierungen in Zapier/Make auslösen
  • Interne Systeme benachrichtigen

2. Verfügbare Veranstaltungen

phone.detected

Haupt-

Es wird ausgelöst, wenn eine neue Telefonnummer in einem Gespräch erkannt wird. Nützlich, um Leads automatisch zu erfassen.

Beispiel-Payload

{
  "event_type": "phone.detected",
  "phone": "+34612345678",
  "detected_at": "2025-01-15T14:30:00Z",
  "shop_id": 123,
  "conversation_hash": "a1b2c3d4e5f6..."
}
Nutzlastfelder
event_type Art der Veranstaltung
phone Erkannte Nummer (E.164)
detected_at Datum/Uhrzeit ISO 8601
shop_id ID deines Shops bei WAzion
conversation_hash Eindeutiger Hash der Unterhaltung

test

Testereignis, das du manuell über das Dashboard auslösen kannst, um zu überprüfen, ob dein Endpunkt korrekt funktioniert.

{
  "event_type": "test",
  "message": "Este es un webhook de prueba desde WAzion",
  "timestamp": "2025-01-15T14:30:00+01:00",
  "shop_id": 123,
  "test": true
}

3. HTTP-Header

WAzion sendet bei jeder Webhook-Anfrage die folgenden Header:

Header Beschreibung Beispiel
Content-Type Inhaltstyp application/json
User-Agent WAzion Kennung WAzion-Webhooks/1.0
X-Webhook-ID Einzigartige Webhook-ID (Format wh_XXXXXXXX) wh_00012345
X-Webhook-Event Art der Veranstaltung phone.detected
X-Webhook-Attempt Versuchsnummer (1-6) 1
X-Webhook-Timestamp Unix-Zeitstempel der Sendung 1705329000
X-Webhook-Signature HMAC-SHA256-Signatur hex (wenn ein Geheimnis vorhanden ist) a1b2c3d4e5f6...

4. HMAC-SHA256-Signatur

Wenn du ein Webhook-Geheimnis einrichtest, signiert WAzion jede Anfrage mit HMAC-SHA256. So kannst du überprüfen, ob die Anfrage tatsächlich von WAzion stammt.

Wie die Unterschrift erzeugt wird

// 1. Concatenar timestamp + "." + payload JSON
signature_payload = timestamp + "." + payload_json

// 2. Calcular HMAC-SHA256 y convertir a hexadecimal
signature = HMAC-SHA256(signature_payload, webhook_secret).toHex()

// 3. El header X-Webhook-Signature contiene la firma directamente:
"a1b2c3d4e5f6789..."  // Sin prefijo, solo el hash hex

Verifizierung in PHP

<?php
function verificarFirmaWebhook($payload, $signatureRecibida, $secret, $timestamp) {
    // Verificar que el timestamp no sea muy antiguo (5 min)
    if (abs(time() - intval($timestamp)) > 300) {
        return false;
    }

    // Construir payload firmado
    $signedPayload = $timestamp . '.' . $payload;

    // Calcular firma esperada
    $expectedSignature = hash_hmac('sha256', $signedPayload, $secret);

    // Comparar de forma segura (timing-safe)
    return hash_equals($expectedSignature, $signatureRecibida);
}

// Uso:
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$secret = 'tu-webhook-secret';

if (!verificarFirmaWebhook($payload, $signature, $secret, $timestamp)) {
    http_response_code(401);
    exit('Firma inválida');
}

Überprüfung in Node.js

const crypto = require('crypto');

function verificarFirmaWebhook(payload, signatureRecibida, secret, timestamp) {
    // Verificar que el timestamp no sea muy antiguo (5 min)
    const currentTime = Math.floor(Date.now() / 1000);
    if (Math.abs(currentTime - parseInt(timestamp)) > 300) {
        return false;
    }

    // Construir payload firmado
    const signedPayload = `${timestamp}.${payload}`;

    // Calcular firma esperada
    const expectedSignature = crypto
        .createHmac('sha256', secret)
        .update(signedPayload)
        .digest('hex');

    // Comparar de forma segura (timing-safe)
    return crypto.timingSafeEqual(
        Buffer.from(signatureRecibida),
        Buffer.from(expectedSignature)
    );
}

Wichtig: Du solltest auch überprüfen, dass der Zeitstempel nicht zu alt ist (z. B. maximal 5 Minuten), um Replay-Angriffe zu verhindern.

5. Technische Spezifikationen

Zeitüberschreitungen

Zeitüberschreitung auf Anfrage 10 Sekunden
Maximum in der Warteschlange 100 webhooks

Wiederholungen

Maximale Anzahl von Versuchen 6
Strategie Exponentielles Backoff

Wiederholungsplan

Versuch 1
Sofortig
Versuch 2
1 min
Versuch 3
5 min
Versuch 4
15 min
Versuch 5
1 hora
Versuch 6
4 horas

Nach dem 6. Versuch wird der Webhook als dauerhafter Fehler markiert.

Akzeptierte Antworten

200 OK 201 Created 202 Accepted 204 No Content

Jeder 2xx-Code gilt als Erfolg.

Codes, die einen erneuten Versuch auslösen

408 Timeout 429 Rate Limit 5xx Server Error

Codes ohne Wiederholungsversuch (dauerhafter Fehler)

400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found

Automatische Duplikaterkennung

WAzion verhindert, dass dieselbe Telefonnummer zweimal gesendet wird. Es wird ein SHA256-Hash jeder gesendeten Telefonnummer gespeichert. Wenn die Telefonnummer bereits zuvor benachrichtigt wurde, wird sie nicht erneut gesendet.

Ratenbegrenzung

Maximal 100 Webhooks in der Warteschlange pro Shop. Wenn das Limit überschritten wird, werden neue Webhooks verworfen. Der Prozessor sendet maximal 50 Webhooks pro Ausführung mit einer Verzögerung von 1 Sekunde zwischen jedem.

Verbindungseinstellungen

Gesamtzeitüberschreitung: 10s
Verbindungszeitüberschreitung: 5s
SSL verifiziert: Ja
Weiterleitungen: Nein

Webhooks folgen keinen Weiterleitungen. Dein Endpunkt muss direkt antworten, ohne weiterzuleiten.

6. Vollständiger Beispielcode

PHP
<?php
// webhook-handler.php

header('Content-Type: application/json');

// Configuración
$webhookSecret = 'tu-webhook-secret'; // Deja vacío si no usas firma

// Obtener datos
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$eventType = $_SERVER['HTTP_X_WEBHOOK_EVENT'] ?? '';

// Verificar firma (si hay secret configurado)
if ($webhookSecret) {
    $expectedSignature = hash_hmac(
        'sha256',
        $timestamp . '.' . $payload,
        $webhookSecret
    );

    if (!hash_equals($expectedSignature, $signature)) {
        http_response_code(401);
        echo json_encode(['error' => 'Invalid signature']);
        exit;
    }

    // Verificar timestamp (máximo 5 minutos de antigüedad)
    if (abs(time() - intval($timestamp)) > 300) {
        http_response_code(401);
        echo json_encode(['error' => 'Timestamp too old']);
        exit;
    }
}

// Decodificar payload
$data = json_decode($payload, true);

// Procesar según tipo de evento
switch ($eventType) {
    case 'phone.detected':
        $phone = $data['phone'];
        $shopId = $data['shop_id'];

        // Guardar en tu base de datos, CRM, etc.
        guardarNuevoLead($phone, $shopId);

        echo json_encode(['status' => 'ok', 'message' => 'Lead saved']);
        break;

    case 'test':
        // Evento de prueba
        echo json_encode(['status' => 'ok', 'message' => 'Test received']);
        break;

    default:
        echo json_encode(['status' => 'ok', 'message' => 'Event not handled']);
}

function guardarNuevoLead($phone, $shopId) {
    // Tu lógica aquí: guardar en BD, enviar a CRM, etc.
    error_log("Nuevo lead: $phone de shop $shopId");
}
Node.js / Express
const express = require('express');
const crypto = require('crypto');

const app = express();
const WEBHOOK_SECRET = 'tu-webhook-secret'; // Deja vacío si no usas firma

// Middleware para raw body
app.use('/webhook', express.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
    const payload = req.body.toString();
    const signature = req.headers['x-webhook-signature'] || '';
    const timestamp = req.headers['x-webhook-timestamp'] || '';
    const eventType = req.headers['x-webhook-event'] || '';

    // Verificar firma (si hay secret)
    if (WEBHOOK_SECRET) {
        const expectedSignature = crypto
            .createHmac('sha256', WEBHOOK_SECRET)
            .update(`${timestamp}.${payload}`)
            .digest('hex');

        const sigBuffer = Buffer.from(signature);
        const expectedBuffer = Buffer.from(expectedSignature);

        if (sigBuffer.length !== expectedBuffer.length ||
            !crypto.timingSafeEqual(sigBuffer, expectedBuffer)) {
            return res.status(401).json({ error: 'Invalid signature' });
        }

        // Verificar timestamp
        if (Math.abs(Date.now() / 1000 - parseInt(timestamp)) > 300) {
            return res.status(401).json({ error: 'Timestamp too old' });
        }
    }

    const data = JSON.parse(payload);

    // Procesar evento
    switch (eventType) {
        case 'phone.detected':
            console.log(`Nuevo lead: ${data.phone} de shop ${data.shop_id}`);
            // Tu lógica aquí
            break;

        case 'test':
            console.log('Test webhook received');
            break;
    }

    res.json({ status: 'ok' });
});

app.listen(3000, () => console.log('Webhook server running on port 3000'));

Änderungsverlauf

Keine kürzlichen Änderungen in dieser Dokumentation.

Verwandte Artikel

WAzion Assistent

Geschäftsinformationen und technischer Support

Hallo! Ich bin der Assistent von WAzion. Ich kann Ihnen mit Informationen zu Preisen und Tarifen, technischen Fragen, der Konfiguration oder jeder anderen Frage zu unserem Produkt helfen. Wie kann ich Ihnen behilflich sein?
Entwickelt mit WAzion AI