Skip to main content

Automatisation par webhooks

Déclenchez des systèmes externes quand les mémoires changent — synchronisation, notification, automatisation.


Automatisation par webhooks

Les webhooks permettent de déclencher des systèmes externes quand des événements Synapse se déclenchent. Ce guide couvre les schémas d'automatisation courants.

Schémas courants

Schéma 1 : notification sur mémoire critique

Envoyez un message Slack quand une mémoire critique est stockée :

# Gestionnaire de webhook (votre serveur)
@app.post("/webhook")
async def handle(request):
    payload = await request.json()
    
    # Vérifier la signature
    if not verify_signature(payload, request.headers):
        return 401
    
    if payload["event"] == "memory.store":
        memory = payload["data"]
        if memory.get("priority") == "critical":
            # Envoyer une notification Slack
            await slack.post(
                f"🚨 Critical memory stored: {memory['key']}\n{memory['content'][:200]}"
            )
    
    return 200

Enregistrez le webhook :

curl -X POST https://synapse.schaefer.zone/webhooks \
  -H "Authorization: Bearer YOUR_MIND_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://my-app.com/webhook",
    "events": "memory.store",
    "secret": "my-hmac-secret"
  }'

Schéma 2 : synchronisation vers système externe

Synchronisez les mémoires vers Notion, Obsidian ou n'importe quelle KB externe :

@app.post("/webhook")
async def sync_to_notion(request):
    payload = await request.json()
    
    if payload["event"] == "memory.store":
        memory = payload["data"]
        # Créer une page Notion
        await notion.create_page(
            title=memory["key"],
            content=memory["content"],
            tags=memory.get("tags", [])
        )
    
    elif payload["event"] == "memory.delete":
        # Supprimer de Notion
        await notion.delete_page(memory_id=payload["data"]["id"])
    
    return 200

Schéma 3 : déclencher CI/CD

Déclenchez un déploiement quand une mémoire « release » est stockée :

@app.post("/webhook")
async def trigger_deploy(request):
    payload = await request.json()
    
    if payload["event"] == "memory.store":
        memory = payload["data"]
        if memory.get("key", "").startswith("release_"):
            # Déclencher le pipeline GitLab
            await gitlab.trigger_pipeline(
                project="synapse",
                ref="main",
                variables={"RELEASE_MEMORY_ID": memory["id"]}
            )
    
    return 200

Schéma 4 : réveiller l'agent sur message humain

Déclenchez une exécution d'agent LLM quand un humain envoie un message de chat :

@app.post("/webhook")
async def wake_agent(request):
    payload = await request.json()
    
    if payload["event"] == "chat.message_received":
        message = payload["data"]
        # Mettre en file le travail de traitement de l'agent
        await job_queue.enqueue(
            "process_message",
            message_id=message["id"],
            content=message["content"]
        )
    
    return 200

Schéma 5 : agréger les métriques

Suivez la croissance de la mémoire, l'activité chat, la complétion des tâches :

@app.post("/webhook")
async def track_metrics(request):
    payload = await request.json()
    event = payload["event"]
    
    metrics = {
        "memory.store": "memories_stored_total",
        "memory.delete": "memories_deleted_total",
        "chat.message_received": "messages_received_total",
        "task.created": "tasks_created_total",
        "task.completed": "tasks_completed_total",
    }
    
    if event in metrics:
        await prometheus.increment(metrics[event])
    
    return 200

Vérification de signature

Vérifiez toujours les signatures de webhook pour empêcher l'usurpation :

import hmac
import hashlib

def verify_signature(payload_body: bytes, headers, secret: str) -> bool:
    signature = headers.get("X-Synapse-Signature", "")
    if not signature.startswith("sha256="):
        return False
    
    expected = hmac.new(
        secret.encode(),
        payload_body,
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(f"sha256={expected}", signature)

Logique de réessai

Synapse réessaie les webhooks échoués avec un backoff exponentiel. Votre gestionnaire devrait :

  1. Renvoyer 200 rapidement — ne pas faire de travail lourd de manière synchrone
  2. Mettre en file le travail — utiliser un système de tâches en arrière-plan
  3. Être idempotent — le même événement peut être livré deux fois
@app.post("/webhook")
async def handle(request):
    payload = await request.json()
    # Mettre en file pour traitement asynchrone
    await job_queue.enqueue("process_webhook", payload)
    # Retourner immédiatement
    return 200

Débogage des webhooks

Consulter l'historique de livraison

Les livraisons de webhook sont journalisées. Vérifiez les livraisons récentes de votre webhook :

# Récupérer les détails du webhook y compris les livraisons récentes
curl -H "Authorization: Bearer YOUR_MIND_KEY" \
     https://synapse.schaefer.zone/webhooks/wh_001

Tester le webhook manuellement

# Déclencher un événement de test
curl -X POST https://synapse.schaefer.zone/webhooks/wh_001/test \
  -H "Authorization: Bearer YOUR_MIND_KEY"

Problèmes courants

Problème Correction
Réponses 4xx Vérifiez que votre gestionnaire renvoie 200
Réponses 5xx Erreur serveur — vérifiez les logs de votre application
Timeout Renvoyez 200 rapidement, mettez le travail en file asynchrone
Livraisons en double Rendez le gestionnaire idempotent
Non-correspondance de signature Vérifiez que le secret est correct

Bonnes pratiques

Prochaines étapes