Guides
Administration
Webhooks

Webhooks & Intégration API

Intégrez CSWeb avec vos applications tierces pour piloter le breakout, gérer les logs et automatiser vos workflows.

CSWeb Community Platform permet deux types d'intégration :

  1. Webhooks entrants : CSPro → CSWeb (événements en temps réel)
  2. API sortante : Application tierce → CSWeb (pilotage du breakout sélectif, logs, monitoring)

Cas d'Usage

1. Piloter le Breakout depuis une Application Tierce

Déclenchez le breakout sélectif d'un dictionnaire spécifique depuis votre dashboard ou application de monitoring.

Exemple : Application de supervision qui lance automatiquement le breakout du dictionnaire MENAGE quand 1000 nouveaux questionnaires sont détectés.

2. Centraliser les Logs dans un SIEM

Envoyez les logs CSWeb vers votre système de monitoring externe (ELK Stack, Splunk, Datadog).

Exemple : Alertes automatiques sur échecs de breakout ou erreurs de synchronisation.

3. Intégration BI/Dashboard

Récupérez les métriques de collecte en temps réel pour alimenter vos dashboards Power BI, Tableau ou Grafana.

Exemple : Dashboard affichant le nombre de questionnaires par région, taux de synchronisation, progression du breakout.


Webhooks racine

CSWeb expose 4 endpoints PHP à la racine, pilotables depuis vos systèmes externes (Kairos, scripts cron, monitoring, BI). Tous partagent :

  • Auth : Authorization: Bearer $BREAKOUT_WEBHOOK_TOKEN
  • Format de réponse uniforme :
    { "success": true,  "data": ... | null, "error": null,             "meta": {...}? }
    { "success": false, "data": null,        "error": { "code": "...", "message": "..." } }
  • Rate-limit : 60 requêtes / 60 secondes par couple (token, IP)
  • Body POST max : 64 KB
EndpointMéthodeRôleDoc
/breakout-webhook.phpPOSTDéclencher un breakout pour un dictionnaireVoir ci-dessous
/breakout-status-webhook.phpGETStatut breakout par dictionnaire (paginé)→ détails
/dictionary-schema-webhook.phpGET / POSTCRUD sur la configuration des cibles breakoutVoir ci-dessous
/log-reader-webhook.phpGETLire les fichiers de log CSWebVoir ci-dessous

Déclencher un breakout

curl -X POST http://csweb.example.com/breakout-webhook.php \
  -H "Authorization: Bearer $BREAKOUT_WEBHOOK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"dictionary": "MENAGE_DICT"}'

Réponse (succès) :

{
  "success": true,
  "data": {
    "dictionary": "MENAGE_DICT",
    "exitCode": 0,
    "output": "Processed 1500 cases…",
    "stderr": "",
    "durationMs": 45230,
    "logFile": "MENAGE_DICT_20260321_103015-api.log"
  },
  "error": null
}

output et stderr sont tronqués à 4 KB par défaut. Pour le contenu complet, soit lire data.logFile via log-reader-webhook.php, soit poser BREAKOUT_WEBHOOK_VERBOSE=1 côté serveur.

Lire le statut consolidé d'un breakout

Voir la page dédiée : Breakout Status Webhook.

Lister / lire les logs

# Lister les logs disponibles
curl -H "Authorization: Bearer $BREAKOUT_WEBHOOK_TOKEN" \
  "http://csweb.example.com/log-reader-webhook.php?action=list"
 
# Lire les 200 dernières lignes d'un fichier
curl -H "Authorization: Bearer $BREAKOUT_WEBHOOK_TOKEN" \
  "http://csweb.example.com/log-reader-webhook.php?file=ui.log&lines=200"

Restrictions :

  • Seuls les fichiers matchant ^[a-zA-Z0-9._-]+\.log$ sont exposés.
  • Le fichier doit physiquement résider dans var/logs/ (pas de symlink échappant).
  • lines borné à 5000.

Configurer la cible breakout d'un dictionnaire

# Enregistrer (ou mettre à jour) la cible — par dict_name OU dict_id
curl -X POST http://csweb.example.com/dictionary-schema-webhook.php \
  -H "Authorization: Bearer $BREAKOUT_WEBHOOK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "register",
    "dictionary_name": "MENAGE_DICT",
    "host_name": "host.docker.internal",
    "schema_name": "menage_breakout",
    "schema_user_name": "csweb",
    "schema_password": "<secret>"
  }'
 
# Lire la config existante
curl -H "Authorization: Bearer $BREAKOUT_WEBHOOK_TOKEN" \
  "http://csweb.example.com/dictionary-schema-webhook.php?action=list"
 
# Supprimer la config (par nom OU id)
curl -X POST http://csweb.example.com/dictionary-schema-webhook.php \
  -H "Authorization: Bearer $BREAKOUT_WEBHOOK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"action": "unregister", "dictionary_name": "MENAGE_DICT"}'

Le schema_password est stocké chiffré (AES_ENCRYPT(?, 'cspro')) en base.

Configuration

Variable d'environnement

# .env (à la racine du projet)
BREAKOUT_WEBHOOK_TOKEN=<32+ octets aléatoires>

Important : la variable est obligatoire. Si elle n'est pas définie, les webhooks répondent 500 server_misconfigured au démarrage. Aucun token par défaut n'est codé en dur.

Pour générer une valeur solide :

openssl rand -hex 32

Puis recréer le container csweb pour pick up la variable :

docker compose up -d --no-deps csweb

Codes d'erreur

Tous les webhooks utilisent le même catalogue de codes (error.code) :

HTTPerror.codeCause
400invalid_bodyJSON invalide ou champs requis manquants
400invalid_dictionaryNom de dict ne matche pas ^[A-Z0-9_]+$
400invalid_filenameNom de fichier log non conforme
400invalid_actionAction inconnue
401missing_tokenHeader Authorization absent ou mal formé
401invalid_tokenToken reçu ne correspond pas
403file_not_readableFichier de log non lisible
404dictionary_not_foundDict inexistant
404file_not_foundFichier de log inexistant
405method_not_allowedVerbe HTTP non supporté
413body_too_largeBody POST > 64 KB
429rate_limitedQuota dépassé (header Retry-After fourni)
500server_misconfiguredBREAKOUT_WEBHOOK_TOKEN non défini
500process_failedproc_open impossible
500breakout_failedBreakout terminé avec exit ≠ 0
500internal_errorErreur DB / exception non spécifique

HTTPS Recommandé

En production, exposer les webhooks uniquement via HTTPS (Let's Encrypt, reverse proxy, etc.). Le Bearer token transite en clair sur HTTP.

Customisation

Webhook Custom

Créer custom-webhook.php à la racine et réutiliser le helper partagé pour hériter automatiquement de l'authentification, du rate-limit, du capping de body et du format de réponse uniforme :

<?php
require_once __DIR__ . '/webhook_helper.php';
 
requireMethod(['POST']);
requireBearerToken();
 
$body = readJsonBody();
if (!$body || empty($body['dictionary'])) {
    respondError('invalid_body', 'Missing "dictionary" in request body.', 400);
}
 
// Logique custom : envoyer une notification Slack
$slack = 'https://hooks.slack.com/services/YOUR/WEBHOOK';
$ch = curl_init($slack);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['text' => "New case in {$body['dictionary']}"]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_exec($ch);
 
respondSuccess(['notified' => true]);

Monitoring

Webhook Deliveries

Tracker succès/échecs :

CREATE TABLE webhook_deliveries (
    id SERIAL PRIMARY KEY,
    webhook_name VARCHAR(50),
    event VARCHAR(50),
    status VARCHAR(20),
    response_time INT,
    created_at TIMESTAMP DEFAULT NOW()
);

Metrics

-- Taux de succès
SELECT
    webhook_name,
    COUNT(*) as total,
    SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as success,
    AVG(response_time) as avg_response_ms
FROM webhook_deliveries
GROUP BY webhook_name;

Troubleshooting

Webhook Non Reçu

Vérifier :

# Firewall
curl http://your-server/breakout-webhook.php
 
# Logs Nginx/Apache
tail -f /var/log/nginx/access.log
 
# Logs CSPro (côté client)

Token Mismatch (401)

# Vérifier le token côté serveur CSWeb
docker exec csweb-app printenv BREAKOUT_WEBHOOK_TOKEN
 
# Vérifier le token côté client (.env de Kairos / variable d'environnement
# de votre intégration). Les deux doivent être strictement identiques.

Réponse attendue en cas de mismatch :

{
  "success": false,
  "data": null,
  "error": { "code": "invalid_token", "message": "Invalid token." }
}

Timeout

Si webhook prend trop de temps :

// Répondre immédiatement
http_response_code(202);
echo json_encode(['status' => 'accepted']);
 
// Traitement async
fastcgi_finish_request();
exec("php process-breakout.php {$dictionary} > /dev/null 2>&1 &");

Ressources