Tutoriel 4 — Webhook événement → Slack
Objectif : recevoir une alerte Slack à chaque facture impayée > 1500 € depuis plus de 30 jours, pour relance immédiate.
Pré-requis
- API key Comptentra scope
read - Workspace Slack avec un Incoming Webhook configuré (URL
https://hooks.slack.com/services/T.../B.../...)
Approche 1 — Polling cron (simple)
Si vous n'avez pas encore d'infra serveur, un cron sur Make / n8n / Zapier suffit.
#!/usr/bin/env bash
# Lancer tous les jours à 09h00 via cron
COMPTENTRA_KEY="${COMPTENTRA_KEY:?}"
SLACK_URL="${SLACK_URL:?}"
# Factures impayées > 1500 € depuis > 30j
THIRTY_DAYS_AGO=$(date -d "30 days ago" +%Y-%m-%d)
curl -s "https://app.comptentra.servolution.fr/api/v1/factures?statut=impayee&min_amount_cents=150000&due_before=$THIRTY_DAYS_AGO" \
-H "X-API-Key: $COMPTENTRA_KEY" | jq -c '.[]' | while read f; do
num=$(echo "$f" | jq -r .numero)
client=$(echo "$f" | jq -r .client_nom)
total=$(echo "$f" | jq -r '.total_cents / 100')
due=$(echo "$f" | jq -r .due_date)
curl -s -X POST "$SLACK_URL" -H 'Content-Type: application/json' -d "{
\"text\": \":warning: Facture impayée *$num* — $client : ${total} € (échéance $due)\"
}"
done
Approche 2 — Webhook sortant Servolution (recommandé)
Configurez un endpoint webhook dans Comptentra → Settings → Webhooks :
- URL : votre receiver (par ex. AWS Lambda, Cloudflare Worker, n8n)
- Events :
invoice.overdue(déclenché 30j après échéance) - Secret HMAC : généré, à conserver pour vérifier la signature header
X-Servolution-Signature
Receiver minimal en Cloudflare Worker :
export default {
async fetch(req, env) {
const body = await req.text();
const sig = req.headers.get("X-Servolution-Signature");
const expected = await hmacSha256(env.WEBHOOK_SECRET, body);
if (sig !== expected) return new Response("bad sig", { status: 401 });
const evt = JSON.parse(body);
if (evt.type === "invoice.overdue" && evt.data.total_cents > 150000) {
await fetch(env.SLACK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `:warning: Facture impayée *${evt.data.numero}* — ${evt.data.client_nom} : ${evt.data.total_cents/100} € (échéance ${evt.data.due_date})`
})
});
}
return new Response("ok");
}
};
async function hmacSha256(key, body) {
const enc = new TextEncoder();
const k = await crypto.subtle.importKey("raw", enc.encode(key),
{ name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
const sig = await crypto.subtle.sign("HMAC", k, enc.encode(body));
return [...new Uint8Array(sig)].map(b => b.toString(16).padStart(2, "0")).join("");
}
3. Bonnes pratiques
- Toujours vérifier la signature HMAC (sinon n'importe qui peut spammer Slack en POSTant sur votre receiver)
- Idempotence : conserver les
event_iddans une KV store / Redis pour ne pas envoyer 2 fois - Throttling : Slack bloque à 1 msg/seconde par webhook (utilisez un canal dédié ou batchez)