Webhooks
Recevez et traitez les événements de paiement sur votre serveur via le proxy ash-gate.
Gestion des Webhooks
ash-gate agit comme un routeur de webhooks. Vos aggrégateurs envoient tous les événements à une seule URL (ash-gate), qui les route automatiquement vers le bon projet.
1. Configurer l'URL de Webhook
Sur votre tableau de bord FedaPay (ou autre aggrégateur), vous devez configurer l'URL de notification. Vous avez deux options :
A. URL Spécifique par Projet (Recommandé)
Chaque projet peut utiliser son propre secret de signature FedaPay défini dans ses paramètres AshGate.
https://app.ashgateway.com/fedapay/webhook/:projectId
Remplacez
:projectIdpar l'ID ou le Slug de votre projet AshGate.
B. URL Globale (Standard)
Utilise le secret de webhook global défini par l'administrateur d'AshGate.
https://app.ashgateway.com/fedapay/webhook
!IMPORTANT L'option A est recommandée car elle permet d'utiliser le secret de webhook (
whsec_...) unique à VOTRE compte FedaPay, garantissant une vérification de signature sécurisée et isolée.
2. Comment ash-gate route les événements
Aggrégateur envoie un événement POST /fedapay/webhooks
│
▼
ash-gate lit : event.metadata.ash_project_id
│
▼
Lookup du projet correspondant en base
│
├──► Vérification de la signature HMAC-SHA256
│
▼
Si webhookUrl configuré dans le projet :
→ Forward de l'événement vers VOTRE serveur
Sinon :
→ Traitement interne (renouvellement d'abonnement, etc.)
3. Configurer votre URL de Callback (optionnel)
Si vous voulez recevoir les événements aussi sur votre propre backend :
# Via la CLI
wallet project update mon-app --webhook-url https://mon-serveur.com/webhooks/fedapay
# Ou directement dans le dashboard ash-gate
4. Recevoir et vérifier les webhooks (NestJS)
import { Controller, Post, Headers, Body, BadRequestException } from '@nestjs/common';
import * as crypto from 'crypto';
@Controller('webhooks')
export class WebhookController {
@Post('fedapay')
handleFedaCloudWebhook(
@Headers('x-feda-signature') signature: string,
@Headers('x-feda-project-id') projectId: string,
@Body() payload: any,
) {
// 1. Vérifier la signature avec votre Secret Key
const expectedSig = crypto
.createHmac('sha256', process.env.FEDA_PROJECT_SECRET)
.update(JSON.stringify(payload))
.digest('hex');
if (signature !== expectedSig) {
throw new BadRequestException('Signature invalide');
}
// 2. Traiter l'événement
const { event, transaction } = payload;
switch (event) {
case 'transaction.approved':
// Activer l'abonnement, débloquer l'accès...
console.log(`Paiement reçu : ${transaction.amount} ${transaction.currency}`);
break;
case 'transaction.canceled':
console.log(`Transaction annulée : ${transaction.id}`);
break;
}
return { received: true };
}
}
5. Recevoir et vérifier les webhooks (Express / Node.js)
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/fedapay', express.json(), (req, res) => {
const signature = req.headers['x-feda-signature'];
const expected = crypto
.createHmac('sha256', process.env.FEDA_PROJECT_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== expected) {
return res.status(400).json({ error: 'Signature invalide' });
}
const { event, transaction } = req.body;
console.log(`Événement reçu : ${event}`, transaction);
res.json({ received: true });
});
Événements supportés
| Événement | Description |
|---|---|
transaction.approved | Le paiement a été validé par l'opérateur mobile |
transaction.declined | Le paiement a été refusé |
transaction.canceled | L'utilisateur a annulé |
transaction.pending | En attente de confirmation |