Guides avancésWebhooks et callbacksIndex

Webhooks et callbacks

Recevez des notifications en temps réel sur l’état de vos transcriptions.


Configuration

Exemple de base

{
  "type": "configure",
  "config": {
    "webhook_url": "https://votre-serveur.com/webhook",
    "webhook_events": [
      "transcription.completed",
      "transcription.failed",
      "session.ended"
    ]
  }
}

Événements disponibles

ÉvénementDescriptionPayload
transcription.completedTranscription finale disponible{session_id, transcription, metadata}
transcription.failedErreur de transcription{session_id, error, metadata}
session.startedSession démarrée{session_id, metadata}
session.endedSession terminée{session_id, duration, metadata}
transcription.partialTranscription partielle (optionnel){session_id, text, status}

Sécurité

Signature HMAC

Tous les webhooks sont signés avec HMAC-SHA256 pour vérifier l’origine.

Header : X-Ephia-Signature

Vérification :

import hmac
import hashlib
 
def verify_signature(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Exemple de gestion (Python/Flask)

from flask import Flask, request
import hmac
import hashlib
import os
 
app = Flask(__name__)
WEBHOOK_SECRET = os.environ.get('EPHIA_WEBHOOK_SECRET')
 
@app.route('/webhook', methods=['POST'])
def webhook():
    # Vérifier la signature
    signature = request.headers.get('X-Ephia-Signature')
    payload = request.get_data()
    
    expected_signature = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    if signature != expected_signature:
        return 'Invalid signature', 401
    
    # Traiter l'événement
    event = request.json
    
    if event['type'] == 'transcription.completed':
        # Sauvegarder la transcription
        save_transcription(event['data'])
    elif event['type'] == 'transcription.failed':
        # Logger l'erreur
        log_error(event['data'])
    
    return 'OK', 200

Exemple de gestion (Node.js/Express)

const express = require('express');
const crypto = require('crypto');
 
const app = express();
const WEBHOOK_SECRET = process.env.EPHIA_WEBHOOK_SECRET;
 
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  // Vérifier la signature
  const signature = req.headers['x-ephia-signature'];
  const payload = req.body;
  
  const expectedSignature = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  if (signature !== expectedSignature) {
    return res.status(401).send('Invalid signature');
  }
  
  // Traiter l'événement
  const event = JSON.parse(payload.toString());
  
  if (event.type === 'transcription.completed') {
    // Sauvegarder la transcription
    saveTranscription(event.data);
  }
  
  res.status(200).send('OK');
});

Retry et gestion d’erreurs

  • Retry automatique : 3 tentatives avec backoff exponentiel
  • Timeout : 30 secondes
  • Format attendu : HTTP 200 avec réponse JSON valide
  • Logs : Disponibles dans le dashboard

Bonnes pratiques

  • ✅ Toujours vérifier la signature HMAC
  • ✅ Implémenter un endpoint idempotent
  • ✅ Logger tous les événements reçus
  • ✅ Gérer les timeouts et erreurs réseau
  • ✅ Tester avec des outils comme ngrok
  • ✅ Utiliser HTTPS pour les webhooks

Test local avec ngrok

# Installer ngrok
npm install -g ngrok
 
# Démarrer votre serveur local
python app.py
 
# Dans un autre terminal, créer un tunnel
ngrok http 5000
 
# Utiliser l'URL ngrok dans la configuration
# https://abc123.ngrok.io/webhook

Format des payloads

transcription.completed

{
  "type": "transcription.completed",
  "session_id": "session_abc123",
  "data": {
    "transcription": "Scanner cérébral sans injection de produit de contraste.",
    "duration": 45.2,
    "metadata": {
      "patient_id": "P12345",
      "consultation_type": "radiologie"
    }
  },
  "timestamp": "2024-12-19T15:30:00Z"
}

transcription.failed

{
  "type": "transcription.failed",
  "session_id": "session_abc123",
  "data": {
    "error": {
      "code": "AUDIO_QUALITY_ERROR",
      "message": "Audio quality too low"
    }
  },
  "timestamp": "2024-12-19T15:30:00Z"
}