Logo GenukaGenuka Pay
Référence API

Webhooks

Configurez vos endpoints webhook et vérifiez les livraisons de manière sécurisée.

Webhooks

Genuka Pay peut notifier votre backend sur les événements transaction, payout, KYC et company.

Headers requis

Les requêtes de gestion d’endpoints webhook doivent inclure :

X-Public-Key: YOUR_PUBLIC_KEY
X-Timestamp: UNIX_TIMESTAMP
X-Signature: HMAC_SHA256_SIGNATURE

Flux recommandé

Les webhooks doivent être gérés depuis le dashboard Genuka Pay, via la page Webhooks.

Ce flux permet à votre équipe :

  • de créer des endpoints
  • de choisir les événements
  • d’activer ou désactiver les endpoints
  • d’inspecter quelques métadonnées de livraison
  • de régénérer le secret

Utilisez l’API ci-dessous seulement pour l’automatisation ou l’outillage interne.

API de gestion

  • GET /api/v1/webhook-endpoints
  • POST /api/v1/webhook-endpoints
  • GET /api/v1/webhook-endpoints/{id}
  • PUT /api/v1/webhook-endpoints/{id}
  • DELETE /api/v1/webhook-endpoints/{id}
  • POST /api/v1/webhook-endpoints/{id}/regenerate-secret

Créer un endpoint

curl -X POST "{{BASE_URL}}/api/v1/webhook-endpoints" \
  -H "X-Public-Key: YOUR_PUBLIC_KEY" \
  -H "X-Timestamp: UNIX_TIMESTAMP" \
  -H "X-Signature: HMAC_SHA256_SIGNATURE" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Backend de production",
    "target_url": "https://merchant.example.com/webhooks/genuka",
    "events": [
      "transaction.success",
      "transaction.failed",
      "payout.success",
      "kyc.approved"
    ],
    "is_active": true
  }'

Événements disponibles

  • transaction.success
  • transaction.failed
  • transaction.processing
  • transaction.refunded
  • payout.success
  • payout.failed
  • payout.processing
  • payout.cancelled
  • kyc.submitted
  • kyc.approved
  • kyc.rejected
  • company.created
  • company.suspended
  • company.reactivated

Forme du payload

{
  "id": "01HW...",
  "event": "transaction.success",
  "timestamp": "2026-09-19T12:10:00.000000Z",
  "data": {
    "transaction_id": "01HR...",
    "idempotency_key": "...",
    "amount": 10000,
    "net_amount": 9575,
    "provider_fee_amount": 150,
    "genuka_fee_amount": 275,
    "total_fee_amount": 425,
    "currency": "XOF",
    "status": "SUCCESS",
    "completed_at": "2026-09-19T12:10:00.000000Z",
    "metadata": { "external_id": "order_10001" }
  }
}

Retrouvez votre propre référence dans data.metadata.external_id, celle que vous avez envoyée à l'initiation.

Headers envoyés :

  • Signature — HMAC-SHA256 de la requête, voir ci-dessous
  • X-Webhook-Id
  • X-Webhook-Event

Vérification de signature

La signature arrive dans le header Signature : un HMAC-SHA256 du corps brut de la requête, avec le secret de l’endpoint.

import crypto from "crypto";

// rawBody : le corps de la requête tel que reçu, avant tout parsing JSON.
function verifyWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");

  const received = Buffer.from(signature, "utf8");
  const computed = Buffer.from(expected, "utf8");

  return (
    received.length === computed.length &&
    crypto.timingSafeEqual(received, computed)
  );
}

Signez le corps brut, pas l’objet reparsé

Re-sérialiser le JSON après l’avoir parsé change les espaces et l’ordre des clés : la signature ne correspondra plus. Gardez le corps brut (express.raw(), request.body non parsé) pour la vérification. Comparez aussi en temps constant, et rejetez toute livraison non signée.

Rotation du secret

curl -X POST "{{BASE_URL}}/api/v1/webhook-endpoints/{id}/regenerate-secret" \
  -H "X-Public-Key: YOUR_PUBLIC_KEY" \
  -H "X-Timestamp: UNIX_TIMESTAMP" \
  -H "X-Signature: HMAC_SHA256_SIGNATURE"

Le nouveau secret doit être stocké immédiatement.

Recommandations

  • retournez un 2xx rapidement
  • poussez le traitement lourd dans une queue
  • vérifiez la signature avant traitement
  • implémentez l’idempotence côté récepteur

How is this guide?

Last updated on