Webhooks
Recevez des notifications en temps réel sur les événements FluenzR.
Webhooks
Les webhooks vous permettent de recevoir des notifications en temps réel lorsque des événements se produisent dans FluenzR.
ℹ️ Info Les webhooks sont disponibles uniquement sur le plan Pro.
Comment ça fonctionne
- Vous configurez une URL de webhook dans FluenzR
- Quand un événement se produit, FluenzR envoie une requête HTTP POST à votre URL
- Votre serveur traite l'événement et répond avec un code 2xx
Événements disponibles
Contacts
| Événement | Description |
|---|---|
contact.created | Nouveau contact créé |
contact.updated | Contact modifié |
contact.deleted | Contact supprimé |
Campagnes
| Événement | Description |
|---|---|
campaign.started | Campagne démarrée |
campaign.paused | Campagne mise en pause |
campaign.completed | Campagne terminée |
Emails
| Événement | Description |
|---|---|
email.sent | Email envoyé |
email.delivered | Email délivré |
email.opened | Email ouvert |
email.clicked | Lien cliqué |
email.replied | Réponse reçue |
email.bounced | Bounce détecté |
email.unsubscribed | Désinscription |
Créer un webhook
Via l'interface
- Allez dans Paramètres > Webhooks
- Cliquez sur + Nouveau webhook
- Configurez l'URL et les événements
- Enregistrez
Via l'API
POST /webhooks
{
"url": "https://your-server.com/webhooks/fluenzr",
"events": [
"email.sent",
"email.opened",
"email.replied"
],
"secret": "your_webhook_secret"
}
Exemple
curl -X POST "https://api.fluenzr.co/v1/webhooks" \
-H "Authorization: Bearer flz_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/fluenzr",
"events": ["email.opened", "email.replied"],
"secret": "whsec_abc123"
}'
Réponse
{
"success": true,
"data": {
"id": "whk_abc123",
"url": "https://your-server.com/webhooks/fluenzr",
"events": ["email.opened", "email.replied"],
"status": "active",
"createdAt": "2025-01-15T10:30:00Z"
}
}
Format des payloads
Structure générale
{
"id": "evt_abc123",
"type": "email.opened",
"timestamp": "2025-01-15T14:32:00Z",
"data": {
// Données spécifiques à l'événement
}
}
email.sent
{
"id": "evt_abc123",
"type": "email.sent",
"timestamp": "2025-01-15T10:00:00Z",
"data": {
"campaignId": "cmp_xyz789",
"campaignName": "Prospection Q1",
"contactId": "con_def456",
"contactEmail": "jean@example.com",
"emailNodeId": "node_2",
"emailSubject": "Jean, question rapide"
}
}
email.opened
{
"id": "evt_abc124",
"type": "email.opened",
"timestamp": "2025-01-15T14:32:00Z",
"data": {
"campaignId": "cmp_xyz789",
"contactId": "con_def456",
"contactEmail": "jean@example.com",
"emailNodeId": "node_2",
"openCount": 1,
"firstOpen": true,
"userAgent": "Mozilla/5.0...",
"ip": "192.168.1.1"
}
}
email.clicked
{
"id": "evt_abc125",
"type": "email.clicked",
"timestamp": "2025-01-15T14:35:00Z",
"data": {
"campaignId": "cmp_xyz789",
"contactId": "con_def456",
"contactEmail": "jean@example.com",
"emailNodeId": "node_2",
"linkUrl": "https://fluenzr.co/demo",
"clickCount": 1
}
}
email.replied
{
"id": "evt_abc126",
"type": "email.replied",
"timestamp": "2025-01-15T15:10:00Z",
"data": {
"campaignId": "cmp_xyz789",
"contactId": "con_def456",
"contactEmail": "jean@example.com",
"emailNodeId": "node_2",
"replySubject": "Re: Jean, question rapide",
"replyPreview": "Bonjour, je serais intéressé par..."
}
}
email.bounced
{
"id": "evt_abc127",
"type": "email.bounced",
"timestamp": "2025-01-15T10:05:00Z",
"data": {
"campaignId": "cmp_xyz789",
"contactId": "con_def456",
"contactEmail": "jean@example.com",
"bounceType": "hard",
"bounceReason": "User unknown"
}
}
contact.created
{
"id": "evt_abc128",
"type": "contact.created",
"timestamp": "2025-01-15T09:00:00Z",
"data": {
"contact": {
"id": "con_def456",
"email": "jean@example.com",
"firstName": "Jean",
"lastName": "Dupont",
"company": "Acme Corp"
}
}
}
Vérification de signature
Chaque webhook inclut une signature pour vérifier son authenticité.
Headers
X-FluenzR-Signature: sha256=abc123...
X-FluenzR-Timestamp: 1640000000
Vérification (Node.js)
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, timestamp, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${payload}`)
.digest('hex');
return `sha256=${expectedSignature}` === signature;
}
// Dans votre endpoint
app.post('/webhooks/fluenzr', (req, res) => {
const signature = req.headers['x-fluenzr-signature'];
const timestamp = req.headers['x-fluenzr-timestamp'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, timestamp, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Traiter l'événement
const event = req.body;
console.log(`Event received: ${event.type}`);
res.status(200).send('OK');
});
Vérification (Python)
import hmac
import hashlib
def verify_webhook_signature(payload, signature, timestamp, secret):
expected = hmac.new(
secret.encode(),
f"{timestamp}.{payload}".encode(),
hashlib.sha256
).hexdigest()
return f"sha256={expected}" == signature
# Dans votre endpoint Flask
@app.route('/webhooks/fluenzr', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-FluenzR-Signature')
timestamp = request.headers.get('X-FluenzR-Timestamp')
payload = request.get_data(as_text=True)
if not verify_webhook_signature(payload, signature, timestamp, WEBHOOK_SECRET):
return 'Invalid signature', 401
event = request.get_json()
print(f"Event received: {event['type']}")
return 'OK', 200
Gestion des retries
FluenzR réessaie automatiquement les webhooks en échec :
| Tentative | Délai |
|---|---|
| 1 | Immédiat |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 heures |
Après 5 échecs, le webhook est marqué comme "failed".
Codes de succès
Votre serveur doit répondre avec un code HTTP 2xx dans les 30 secondes.
| Code | Résultat |
|---|---|
| 200-299 | Succès |
| 3xx | Retry |
| 4xx | Échec permanent |
| 5xx | Retry |
| Timeout | Retry |
Gérer les webhooks
Lister les webhooks
GET /webhooks
Modifier un webhook
PUT /webhooks/:id
{
"events": ["email.opened", "email.replied", "email.clicked"]
}
Supprimer un webhook
DELETE /webhooks/:id
Tester un webhook
POST /webhooks/:id/test
Envoie un événement de test à votre URL.
Voir les logs
GET /webhooks/:id/logs
Récupère l'historique des tentatives de livraison.
{
"success": true,
"data": [
{
"id": "log_abc123",
"eventId": "evt_xyz789",
"eventType": "email.opened",
"status": "delivered",
"statusCode": 200,
"responseTime": 145,
"timestamp": "2025-01-15T14:32:00Z"
}
]
}
Bonnes pratiques
Répondre rapidement
Votre endpoint doit répondre en moins de 30 secondes. Effectuez le traitement en arrière-plan si nécessaire.
Idempotence
Votre code doit gérer les événements dupliqués. Utilisez l'ID de l'événement pour dédupliquer.
Monitoring
Surveillez vos webhooks :
- Taux de succès
- Temps de réponse
- Erreurs fréquentes
Sécurité
- Vérifiez toujours la signature
- Utilisez HTTPS uniquement
- Validez le timestamp (rejeter si > 5 minutes)
