Webhooks

Créer un endpoint

POST /webhook-endpoints · permission webhooks:write · idempotent

BASH
curl -X POST https://api.click2call.app/v1/webhook-endpoints \
  -H "Authorization: Bearer $CLICK2CALL_API_KEY" \
  -H "Idempotency-Key: webhook-production" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://exemple.fr/webhooks/click2call","events":["call.connected","call.completed","callback.requested"]}'

Le secret n'est renvoyé qu'à la création. Les endpoints doivent être HTTPS et ne peuvent pas cibler un réseau privé.

Événements

call.requested, call.ringing, call.connected, call.completed, call.failed et callback.requested.

JSON
{"id":"01K...","event":"call.completed","created_at":"2026-07-31T10:04:42Z","data":{"id":"01K...","workspace_id":"01K...","status":"completed","duration_seconds":210}}

Vérifier la signature

L'en-tête Click2Call-Signature suit t=timestamp,v1=signature. La signature est le HMAC-SHA256 de timestamp + "." + corps_brut.

Vérification sans SDK
import crypto from 'node:crypto';

const parts = Object.fromEntries(signatureHeader.split(',').map((part) => part.split('=')));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) throw new Error('Signature expirée');
const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))) throw new Error('Signature invalide');

Utilisez le corps brut, comparez en temps constant et rejetez un timestamp vieux de plus de 300 secondes. Dédupliquez avec l'identifiant id.

Administration

  • GET /webhook-endpoints
  • PATCH /webhook-endpoints/{id} · idempotent
  • DELETE /webhook-endpoints/{id}
  • GET /webhook-deliveries
  • POST /webhook-deliveries/{id}/retry · idempotent