CENTRE D’AIDE

Webhooks

Recevez des notifications HTTP automatiques sur votre serveur lorsque des événements importants se produisent dans WAzion.

1. Introduction

Les webhooks permettent à votre serveur de recevoir des notifications automatiques lorsqu’événements spécifiques se produisent dans WAzion. Au lieu de consulter périodiquement s’il y a des nouveautés, WAzion envoie une requête HTTP POST à votre serveur lorsqu’un événement important survient.

Comment ça fonctionne ?

  1. 1 Vous configurez une URL de votre serveur dans le tableau de bord de WAzion
  2. 2 Tu sélectionnez les événements que vous souhaitez recevoir
  3. 3 Lorsqu’un événement se produit, WAzion envoie un POST à votre URL
  4. 4 Votre serveur traite l’événement et répond avec HTTP 200

Cas d’utilisation

  • Synchroniser de nouveaux contacts avec votre CRM
  • Créer des prospects automatiquement
  • Déclencher des automatisations sur Zapier/Make
  • Notifier les systèmes internes

2. Événements disponibles

phone.detected

Principal

Il se déclenche lorsqu’un nouveau numéro de téléphone est détecté dans une conversation. Utile pour capturer des prospects automatiquement.

Exemple de charge utile

{
  "event_type": "phone.detected",
  "phone": "+34612345678",
  "detected_at": "2025-01-15T14:30:00Z",
  "shop_id": 123,
  "conversation_hash": "a1b2c3d4e5f6..."
}
Champs de la charge utile
event_type Type d’événement
phone Numéro détecté (E.164)
detected_at Date/heure ISO 8601
shop_id ID de ta boutique sur WAzion
conversation_hash Hash unique de la conversation

test

Événement de test que vous pouvez déclencher manuellement depuis le tableau de bord pour vérifier que votre point de terminaison fonctionne correctement.

{
  "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. En-têtes HTTP

WAzion envoie les en-têtes suivants dans chaque requête webhook :

Header Description Exemple
Content-Type Type de contenu application/json
User-Agent Identifiant de WAzion WAzion-Webhooks/1.0
X-Webhook-ID ID unique du webhook (format wh_XXXXXXXX) wh_00012345
X-Webhook-Event Type d’événement phone.detected
X-Webhook-Attempt Numéro de tentative (1-6) 1
X-Webhook-Timestamp Timestamp Unix d’envoi 1705329000
X-Webhook-Signature Signature HMAC-SHA256 hexadécimale (si secret) a1b2c3d4e5f6...

4. Signature HMAC-SHA256

Si vous configurez un secret webhook, WAzion signera chaque requête en utilisant HMAC-SHA256. Cela vous permet de vérifier que la requête provient réellement de WAzion.

Comment la signature est-elle générée

// 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

Vérification en 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');
}

Vérification en 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)
    );
}

Important : Tu devrais également vérifier que le timestamp ne soit pas trop ancien (ex : maximum 5 minutes) pour prévenir les attaques de rejeu.

5. Spécifications Techniques

Délai d’attente

Temps d’attente demandé 10 secondes
Maximum en file d’attente 100 webhooks

Tentatives répétées

Nombre maximum de tentatives 6
Stratégie Recul exponentiel

Calendrier de nouvelles tentatives

Essai 1
Immédiat
Essai 2
1 min
Essai 3
5 min
Essai 4
15 min
Essai 5
1 hora
Essai 6
4 horas

Après la sixième tentative, le webhook est considéré comme un échec permanent.

Réponses acceptées

200 OK 201 Created 202 Accepted 204 No Content

Tout code 2xx est considéré comme un succès.

Codes qui activent la nouvelle tentative

408 Timeout 429 Rate Limit 5xx Server Error

Codes sans nouvelle tentative (échec permanent)

400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found

Déduplication automatique

WAzion évite d’envoyer deux fois le même numéro de téléphone. Un hash SHA256 de chaque téléphone envoyé est stocké. Si le téléphone a déjà été notifié auparavant, il n’est pas renvoyé.

Limitation de débit

Maximum 100 webhooks en file d’attente par boutique. Si la limite est dépassée, les nouveaux webhooks sont rejetés. Le processeur envoie au maximum 50 webhooks par exécution avec un délai d’une seconde entre chacun.

Configuration de la connexion

Temps d’attente total: 10s
Délai de connexion dépassé: 5s
SSL vérifié: Oui
Redirections: Non

Les webhooks NE suivent PAS les redirections. Votre point de terminaison doit répondre directement sans rediriger.

6. Code d’exemple complet

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'));

Historique des modifications

Pas de modifications récentes dans cette documentation.

Articles connexes

Assistant WAzion

Informations commerciales et support technique

Bonjour ! Je suis l’assistant de WAzion. Je peux vous aider avec des informations sur les tarifs et les plans, des questions techniques, la configuration, ou toute autre question concernant notre produit. Comment puis-je vous aider ?
Développé avec WAzion AI