v1.0 Novembre 2025
7.2

Spécifications Webhooks

Notifications temps réel pour une intégration fluide

24 novembre 2025
Version 1.0
1

VUE D'ENSEMBLE

1.1 Objectif du Document

Ce document spécifie l'ensemble des webhooks fournis par la plateforme REWAPP. Les webhooks permettent aux systèmes partenaires de recevoir des notifications en temps réel lors d'événements spécifiques au sein de l'écosystème REWAPP.

WEBHOOKS

Les webhooks constituent un mécanisme push permettant d'éviter le polling constant de l'API et d'assurer une réactivité optimale dans le traitement des événements métier.

1.2 Principes des Webhooks REWAPP

  • Notifications temps réel Envoi immédiat après chaque événement (latence < 500ms)
  • Sécurité par signature Chaque webhook est signé via HMAC-SHA256
  • Garantie de livraison Politique de retry avec backoff exponentiel
  • Idempotence Chaque événement possède un identifiant unique pour le dédoublonnage
  • Format standardisé Structure JSON cohérente pour tous les événements

1.3 Architecture Générale

Architecture
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────────┐
│  Événement      │────▶│  Queue de        │────▶│  Endpoint           │
│  REWAPP         │     │  Messages (Bull) │     │  Partenaire         │
│  (Transaction,  │     │                  │     │  (HTTPS POST)       │
│  Points, QR...) │     │  Redis           │     │                     │
└─────────────────┘     └──────────────────┘     └─────────────────────┘
                                │
                                ▼
                        ┌──────────────────┐
                        │  Retry Manager   │
                        │  (Backoff Exp.)  │
                        └──────────────────┘

Flux de traitement

  1. 1
    Événement métier

    Un événement se produit dans REWAPP (transaction, crédit points, scan QR...)

  2. 2
    Publication dans la queue

    L'événement est publié dans la queue Bull (Redis)

  3. 3
    Construction du payload

    Le worker webhook récupère l'événement et construit le payload

  4. 4
    Signature HMAC

    Le payload est signé avec le secret HMAC du partenaire

  5. 5
    Envoi HTTPS

    La requête POST HTTPS est envoyée à l'endpoint configuré

  6. 6
    Retry si échec

    En cas d'échec, le Retry Manager planifie les réessais

2

CONFIGURATION DES WEBHOOKS

2.1 Enregistrement d'un Endpoint

Les partenaires peuvent configurer leurs webhooks via le Dashboard Partenaire ou via l'API de configuration.

Via Dashboard Partenaire

  1. 1

    Accéder à « Paramètres » → « Webhooks »

  2. 2

    Cliquer sur « Ajouter un endpoint »

  3. 3

    Renseigner l'URL HTTPS de réception

  4. 4

    Sélectionner les événements à recevoir

  5. 5

    Copier le secret généré automatiquement

  6. 6

    Valider la configuration

Via API

POST /api/v1/webhooks/endpoints

Enregistre un nouvel endpoint webhook pour le partenaire.

Requête
JSON
{
  "url": "https://example.com/webhooks/rewapp",
  "events": [
    "transaction.created",
    "transaction.validated",
    "points.credited",
    "qr_code.scanned"
  ],
  "description": "Endpoint production",
  "active": true
}
Réponse 201 Created
JSON
{
  "id": "wh_endpoint_a1b2c3d4e5f6",
  "url": "https://example.com/webhooks/rewapp",
  "events": ["transaction.created", "transaction.validated", "points.credited", "qr_code.scanned"],
  "secret": "whsec_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456",
  "active": true,
  "created_at": "2025-11-24T10:30:00Z"
}
IMPORTANT

Le secret n'est affiché qu'une seule fois lors de la création. Il doit être stocké de manière sécurisée.

2.2 Paramètres de Configuration

Paramètres

Paramètre Type Obligatoire Description
url string Oui URL HTTPS de l'endpoint (TLS 1.2+ requis)
events array Oui Liste des événements à recevoir
description string Non Description libre de l'endpoint
active boolean Non Statut actif/inactif (défaut: true)
metadata object Non Métadonnées personnalisées

Contraintes techniques

  • URL obligatoirement en HTTPS (HTTP non autorisé)
  • TLS version 1.2 minimum
  • Port standard (443) ou ports autorisés (8443, 8080)
  • Timeout de connexion : 5 secondes
  • Timeout de réponse : 10 secondes
  • Taille maximale payload : 64 Ko

2.3 Gestion des Secrets

Chaque endpoint webhook possède un secret unique utilisé pour signer les requêtes.

POST /api/v1/webhooks/endpoints/{endpoint_id}/rotate-secret

Régénère le secret HMAC de l'endpoint.

Réponse 200 OK
JSON
{
  "id": "wh_endpoint_a1b2c3d4e5f6",
  "new_secret": "whsec_NewSecretKey987654321AbCdEfGh",
  "old_secret_valid_until": "2025-11-25T10:30:00Z"
}
PÉRIODE DE GRÂCE

L'ancien secret reste valide pendant 24 heures pour permettre une transition sans interruption.

3

ÉVÉNEMENTS DISPONIBLES

3.1 Événements Transactions

Transactions

ÉvénementDescriptionDéclencheur
transaction.createdNouvelle transaction détectéeDétection d'un achat via carte liée
transaction.validatedTransaction validéeValidation après période de contestation
transaction.cancelledTransaction annuléeAnnulation par le commerçant ou remboursement
transaction.disputedTransaction contestéeLitige ouvert par l'utilisateur

3.2 Événements Points

Points

ÉvénementDescriptionDéclencheur
points.creditedPoints crédités au compteValidation transaction ou bonus
points.debitedPoints débités du compteUtilisation QR code ou virement
points.expiredPoints expirésExpiration après 12 mois d'inactivité
points.transferredPoints transférésTransfert entre comptes (si activé)

3.3 Événements QR Code

QR Codes

ÉvénementDescriptionDéclencheur
qr_code.generatedQR code généréGénération par l'utilisateur mobile
qr_code.scannedQR code scanné avec succèsScan validé par le partenaire
qr_code.expiredQR code expiréExpiration après 60 secondes
qr_code.rejectedQR code rejetéScan échoué (solde insuffisant, déjà utilisé...)

3.4 Événements Utilisateur

Utilisateurs

ÉvénementDescriptionDéclencheur
user.registeredNouvel utilisateur inscritFinalisation inscription
user.card_linkedCarte bancaire liéeLiaison réussie via OpenBanking
user.card_unlinkedCarte bancaire suppriméeSuppression par l'utilisateur
user.tier_upgradedPalier fidélité augmentéPassage au palier supérieur
user.tier_downgradedPalier fidélité réduitRétrogradation de palier

3.5 Événements Partenaire

Partenaires

ÉvénementDescriptionDéclencheur
partner.validatedPartenaire validéValidation par l'admin REWAPP
partner.suspendedPartenaire suspenduSuspension du compte partenaire
partner.settings_updatedParamètres modifiésModification taux cashback ou config

3.6 Événements Campagne

Campagnes

ÉvénementDescriptionDéclencheur
campaign.createdNouvelle campagne crééeCréation campagne promotionnelle
campaign.startedCampagne démarréeDébut de la période active
campaign.endedCampagne terminéeFin de la période ou objectif atteint
campaign.cancelledCampagne annuléeAnnulation manuelle
4

FORMAT DES PAYLOADS

4.1 Structure Générale

Tous les webhooks REWAPP suivent une structure JSON standardisée :

JSON
{
  "id": "evt_a1b2c3d4e5f6g7h8i9j0",
  "type": "transaction.validated",
  "api_version": "2025-11-01",
  "created_at": "2025-11-24T14:35:22.123Z",
  "livemode": true,
  "data": {
    "object": { ... }
  },
  "metadata": {
    "source": "api",
    "correlation_id": "req_xyz789"
  }
}

Champs du Payload

ChampTypeDescription
idstringIdentifiant unique de l'événement (format: evt_*)
typestringType d'événement (ex: transaction.validated)
api_versionstringVersion de l'API utilisée
created_atstringTimestamp ISO 8601 de création
livemodebooleantrue = production, false = test
data.objectobjectDonnées spécifiques à l'événement
metadataobjectMétadonnées contextuelles

4.2 En-têtes HTTP

Chaque requête webhook inclut les en-têtes suivants :

En-têtes

En-têteValeurDescription
Content-Typeapplication/jsonType de contenu
X-Rewapp-Signaturehmac-sha256=...Signature HMAC de la requête
X-Rewapp-Eventtransaction.validatedType d'événement
X-Rewapp-Deliverydlv_a1b2c3d4Identifiant unique de la livraison
X-Rewapp-Timestamp1732456522Timestamp Unix de l'envoi
User-AgentREWAPP-Webhook/1.0Agent utilisateur

4.3 Corps de la Requête

Le corps est toujours au format JSON UTF-8. Les dates sont au format ISO 8601. Les montants sont en centimes (integer) pour éviter les erreurs de floating point.

CONVENTIONS
  • Montants : en centimes (10000 = 100,00€)
  • Points : en unités entières (100 points = 10,00€)
  • Dates : ISO 8601 avec timezone UTC
  • Identifiants : préfixés par type (usr_, txn_, pts_, qr_...)

4.4 Exemples de Payloads

transaction.validated

JSON
{
  "id": "evt_txn_validated_20251124143522",
  "type": "transaction.validated",
  "api_version": "2025-11-01",
  "created_at": "2025-11-24T14:35:22.123Z",
  "livemode": true,
  "data": {
    "object": {
      "id": "txn_a1b2c3d4e5f6",
      "user_id": "usr_x1y2z3",
      "partner_id": "ptn_m1n2o3",
      "amount": 5000,
      "currency": "EUR",
      "cashback_rate": 4.0,
      "points_earned": 20,
      "status": "validated",
      "card_last_four": "4242",
      "merchant_name": "Boulangerie Martin",
      "transaction_date": "2025-11-24T10:15:00Z",
      "validated_at": "2025-11-24T14:35:22Z"
    }
  },
  "metadata": { "source": "card_linking", "correlation_id": "req_abc123" }
}

points.credited

JSON
{
  "id": "evt_pts_credited_20251124143530",
  "type": "points.credited",
  "api_version": "2025-11-01",
  "created_at": "2025-11-24T14:35:30.456Z",
  "livemode": true,
  "data": {
    "object": {
      "id": "pts_credit_a1b2c3",
      "user_id": "usr_x1y2z3",
      "amount": 20,
      "balance_after": 520,
      "source_type": "transaction",
      "source_id": "txn_a1b2c3d4e5f6",
      "description": "Cashback Boulangerie Martin",
      "expires_at": "2026-11-24T14:35:30Z"
    }
  },
  "metadata": { "tier": "silver", "bonus_applied": 5 }
}

qr_code.scanned

JSON
{
  "id": "evt_qr_scanned_20251124150000",
  "type": "qr_code.scanned",
  "api_version": "2025-11-01",
  "created_at": "2025-11-24T15:00:00.789Z",
  "livemode": true,
  "data": {
    "object": {
      "id": "qr_scan_x1y2z3",
      "qr_code_id": "qr_a1b2c3d4",
      "user_id": "usr_x1y2z3",
      "partner_id": "ptn_m1n2o3",
      "points_used": 100,
      "euro_value": 1050,
      "scanned_at": "2025-11-24T15:00:00Z",
      "scanner_device": "iPad Pro",
      "location": { "latitude": 48.8566, "longitude": 2.3522 }
    }
  },
  "metadata": { "app_version": "2.1.0" }
}
5

SÉCURITÉ DES WEBHOOKS

5.1 Signature HMAC-SHA256

Chaque webhook est signé avec le secret HMAC du partenaire pour garantir l'authenticité et l'intégrité des données.

Mécanisme de signature

  1. 1

    Concaténation du timestamp et du body JSON

  2. 2

    Calcul du hash HMAC-SHA256 avec le secret

  3. 3

    Envoi de la signature dans l'en-tête X-Rewapp-Signature

Pseudo-code
timestamp = current_unix_timestamp()
payload = JSON.stringify(webhook_body)
signed_payload = timestamp + "." + payload
signature = HMAC_SHA256(secret, signed_payload)
header = "t=" + timestamp + ",v1=" + signature

Format de l'en-tête X-Rewapp-Signature :

Header
X-Rewapp-Signature: t=1732456522,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

5.2 Validation de la Signature

Le récepteur DOIT valider la signature avant de traiter l'événement.

Étapes de validation

  1. 1

    Extraire le timestamp (t) et la signature (v1) de l'en-tête

  2. 2

    Vérifier que le timestamp n'est pas trop ancien (< 5 minutes)

  3. 3

    Reconstruire le signed_payload : timestamp + "." + raw_body

  4. 4

    Calculer le HMAC-SHA256 avec le secret stocké

  5. 5

    Comparer la signature (comparaison timing-safe)

Exemple Node.js

JavaScript
const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signature, secret) {
  const elements = signature.split(',');
  const timestamp = elements.find(e => e.startsWith('t=')).slice(2);
  const receivedSig = elements.find(e => e.startsWith('v1=')).slice(3);
  
  // Vérifier la fraîcheur du timestamp (5 min max)
  const currentTime = Math.floor(Date.now() / 1000);
  if (currentTime - parseInt(timestamp) > 300) {
    throw new Error('Timestamp too old');
  }
  
  // Calculer la signature attendue
  const signedPayload = timestamp + '.' + rawBody;
  const expectedSig = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  // Comparaison timing-safe
  if (!crypto.timingSafeEqual(
    Buffer.from(receivedSig),
    Buffer.from(expectedSig)
  )) {
    throw new Error('Invalid signature');
  }
  
  return JSON.parse(rawBody);
}

Exemple Python

Python
import hmac
import hashlib
import time
import json

def verify_webhook_signature(raw_body, signature, secret):
    elements = dict(e.split('=') for e in signature.split(','))
    timestamp = elements['t']
    received_sig = elements['v1']
    
    # Vérifier la fraîcheur (5 min max)
    if int(time.time()) - int(timestamp) > 300:
        raise ValueError('Timestamp too old')
    
    # Calculer la signature attendue
    signed_payload = f"{timestamp}.{raw_body}"
    expected_sig = hmac.new(
        secret.encode(),
        signed_payload.encode(),
        hashlib.sha256
    ).hexdigest()
    
    # Comparaison timing-safe
    if not hmac.compare_digest(received_sig, expected_sig):
        raise ValueError('Invalid signature')
    
    return json.loads(raw_body)

5.3 Bonnes Pratiques de Sécurité

À FAIRE
  • Toujours valider la signature AVANT tout traitement
  • Utiliser une comparaison timing-safe
  • Rejeter les webhooks avec timestamp > 5 minutes
  • Stocker le secret de manière sécurisée
  • Utiliser HTTPS avec TLS 1.2+
  • Logger les échecs de validation
À ÉVITER
  • Ne jamais exposer le secret dans le code source
  • Ne pas désactiver la validation de signature
  • Ne pas utiliser HTTP (toujours HTTPS)
  • Ne pas faire confiance aux données sans validation
6

POLITIQUE DE RETRY

6.1 Mécanisme de Réessai

En cas d'échec de livraison d'un webhook, REWAPP applique automatiquement une politique de retry.

CRITÈRES D'ÉCHEC
  • Timeout de connexion (> 5 secondes)
  • Timeout de réponse (> 10 secondes)
  • Code HTTP 5xx (erreur serveur)
  • Code HTTP 429 (rate limiting)
  • Erreur réseau (DNS, connexion refusée...)
CRITÈRES DE SUCCÈS
  • Code HTTP 200 OK
  • Code HTTP 201 Created
  • Code HTTP 202 Accepted
  • Code HTTP 204 No Content
ATTENTION

Les codes 4xx (sauf 429) sont considérés comme des échecs définitifs et ne déclenchent PAS de retry.

6.2 Backoff Exponentiel

REWAPP utilise un algorithme de backoff exponentiel avec jitter pour espacer les tentatives.

Délais de Retry

TentativeDélai après échecDélai cumulé
1Immédiat0
21 minute1 min
35 minutes6 min
430 minutes36 min
52 heures2h36
66 heures8h36
712 heures20h36
824 heures (abandon)44h36
Formule
delay = min(base_delay * (2 ^ attempt) + random_jitter, max_delay)

Où :
  - base_delay = 60 secondes
  - max_delay = 86400 secondes (24h)
  - random_jitter = 0 à 30 secondes

6.3 Gestion des Échecs

Après 8 tentatives échouées :

  • L'événement est marqué comme « failed »
  • Une alerte est envoyée au partenaire (email + notification dashboard)
  • L'événement reste consultable dans l'historique pendant 30 jours
  • Le partenaire peut déclencher un renvoi manuel via le dashboard
POST /api/v1/webhooks/events/{event_id}/retry

Déclenche manuellement un renvoi de l'événement.

GET /api/v1/webhooks/events?status=failed&from=2025-11-01&to=2025-11-24

Récupère la liste des événements en échec.

7

IMPLÉMENTATION CÔTÉ RÉCEPTEUR

7.1 Exigences Techniques

Exigences

ExigenceValeurObligatoire
ProtocoleHTTPS (TLS 1.2+) Oui
Méthode HTTPPOST Oui
Content-Type acceptéapplication/json Oui
Temps de réponse< 10 secondes Oui
Code de succès2xx Oui
IdempotenceGestion des doublonsRecommandé

7.2 Traitement des Événements

Workflow recommandé

  1. 1

    Recevoir la requête POST

  2. 2

    Valider la signature HMAC (rejeter si invalide)

  3. 3

    Parser le JSON

  4. 4

    Vérifier l'idempotence (event_id déjà traité ?)

  5. 5

    Répondre 200 OK immédiatement

  6. 6

    Traiter l'événement de manière asynchrone

IMPORTANT

Répondre rapidement (< 10s) même si le traitement est long. Utiliser une queue interne pour le traitement asynchrone.

Exemple d'endpoint (Express.js)

JavaScript
const express = require('express');
const app = express();

app.post('/webhooks/rewapp', 
  express.raw({type: 'application/json'}), 
  async (req, res) => {
    const signature = req.headers['x-rewapp-signature'];
    const rawBody = req.body.toString();
    
    try {
      // 1. Valider la signature
      const event = verifyWebhookSignature(rawBody, signature, WEBHOOK_SECRET);
      
      // 2. Vérifier l'idempotence
      if (await isEventAlreadyProcessed(event.id)) {
        return res.status(200).send('Already processed');
      }
      
      // 3. Répondre immédiatement
      res.status(200).send('Received');
      
      // 4. Traiter de manière asynchrone
      await queueEventForProcessing(event);
      
    } catch (error) {
      console.error('Webhook error:', error);
      return res.status(400).send('Invalid webhook');
    }
});

7.3 Gestion de l'Idempotence

Chaque événement possède un identifiant unique (champ id). Le récepteur DOIT implémenter une logique d'idempotence pour éviter de traiter plusieurs fois le même événement.

Stratégies recommandées

  • Table de déduplication : Stocker les event_id traités avec TTL de 7 jours
  • Clé unique en base : Utiliser event_id comme clé unique
  • Cache distribué : Redis avec SETNX pour vérification atomique
JavaScript (Redis)
async function isEventAlreadyProcessed(eventId) {
  const key = 'webhook:processed:' + eventId;
  const result = await redis.set(key, '1', 'NX', 'EX', 604800); // 7 jours
  return result === null; // null = clé existait déjà
}
8

MONITORING ET DEBUGGING

8.1 Logs des Webhooks

Tous les webhooks envoyés sont loggés et consultables via le Dashboard Partenaire ou l'API.

Informations disponibles

  • Identifiant de l'événement
  • Type d'événement
  • Timestamp d'envoi
  • Statut de livraison (pending, delivered, failed)
  • Nombre de tentatives
  • Code de réponse HTTP
  • Temps de réponse
  • Payload envoyé

8.2 Tableau de Bord des Livraisons

Accessible via : Dashboard Partenaire → Webhooks → Historique

Fonctionnalités

Filtres Par type, statut, période
Export Export CSV
Détail Détail de chaque livraison
Renvoi Renvoi manuel

8.3 Outils de Test

REWAPP fournit un endpoint pour tester la configuration webhook sans générer de vrais événements.

POST /api/v1/webhooks/endpoints/{endpoint_id}/test

Envoie un webhook de test à l'endpoint configuré.

Requête
JSON
{
  "event_type": "transaction.validated"
}
Réponse 200 OK
JSON
{
  "success": true,
  "delivery_id": "dlv_test_a1b2c3",
  "response_code": 200,
  "response_time_ms": 145,
  "message": "Test webhook delivered successfully"
}
MODE SANDBOX

En environnement sandbox, les webhooks sont envoyés avec livemode: false. Cela permet de tester l'intégration sans affecter les données de production.

9

CODES D'ERREUR

9.1 Codes de Réponse HTTP

Codes que le récepteur DOIT retourner :

Codes HTTP

CodeSignificationAction REWAPP
200OKLivraison confirmée
201CreatedLivraison confirmée
202AcceptedLivraison confirmée
204No ContentLivraison confirmée
400Bad RequestÉchec définitif (pas de retry)
401UnauthorizedÉchec définitif (pas de retry)
403ForbiddenÉchec définitif (pas de retry)
404Not FoundÉchec définitif (pas de retry)
429Too Many RequestsRetry avec backoff
500Internal Server ErrorRetry avec backoff
502Bad GatewayRetry avec backoff
503Service UnavailableRetry avec backoff
504Gateway TimeoutRetry avec backoff

9.2 Codes d'Erreur Métier

Erreurs retournées par l'API de configuration webhooks :

Erreurs Métier

CodeMessageDescription
WEBHOOK_URL_INVALIDURL invalide ou non HTTPSL'URL doit être HTTPS valide
WEBHOOK_URL_UNREACHABLEEndpoint injoignableImpossible de contacter l'URL
WEBHOOK_EVENT_UNKNOWNType d'événement inconnuEvent type non reconnu
WEBHOOK_LIMIT_REACHEDLimite d'endpoints atteinteMaximum 10 endpoints par partenaire
WEBHOOK_SECRET_ROTATION_FAILEDÉchec rotation secretErreur lors de la régénération
WEBHOOK_ENDPOINT_NOT_FOUNDEndpoint non trouvéID endpoint invalide
WEBHOOK_DELIVERY_FAILEDÉchec de livraisonToutes les tentatives ont échoué
10

RÉCAPITULATIF

10.1 Points Clés

  • Architecture robuste : Queue Bull + Redis pour garantie de livraison
  • Sécurité maximale : Signature HMAC-SHA256 sur chaque webhook
  • Retry intelligent : Backoff exponentiel jusqu'à 8 tentatives sur 44 heures
  • 14 types d'événements : Transactions, points, QR codes, utilisateurs, partenaires, campagnes
  • Monitoring complet : Dashboard, logs, outils de test

10.2 Checklist d'Intégration

  • Configurer l'endpoint HTTPS (TLS 1.2+)
  • Stocker le secret de manière sécurisée
  • Implémenter la validation de signature HMAC-SHA256
  • Implémenter la gestion d'idempotence
  • Répondre en moins de 10 secondes
  • Traiter les événements de manière asynchrone
  • Tester avec l'endpoint de test REWAPP
  • Monitorer les livraisons via le dashboard

10.3 Support

Documentation docs.rewapp.com/webhooks
Exemples github.com/rewapp/webhook-examples
Support support-tech@rewapp.com
Status status.rewapp.com

« Les webhooks REWAPP : la notification en temps réel pour une intégration fluide »