Workflow complet d’un paiement, de la création server-side jusqu’à la confirmation webhook.

1. Installer le SDK

npm install izichangepay-sdk

2. Initialiser le client

// lib/izipay.ts
import { IziPayClient } from 'izichangepay-sdk';

if (!process.env.IZIPAY_API_KEY) {
  throw new Error('IZIPAY_API_KEY is required');
}

export const izipay = new IziPayClient({
  apiKey: process.env.IZIPAY_API_KEY,
});

3. Créer le payment intent

Côté backend, créez le PaymentIntent au moment du checkout, puis redirigez le client.
// pages/api/checkout.ts (Next.js API route, Express, etc.)
import { izipay } from '../../lib/izipay';

export default async function handler(req, res) {
  const { orderId, totalXof } = req.body;

  const intent = await izipay.paymentIntents.create({
    requestedCurrencyType: 'fiat',
    currencyRequested: 'XOF',
    // Chaîne décimale en unité majeure (ex "5000" = 5000 XOF), jamais des centimes ni un number JSON.
    amountRequested: totalXof,
    acceptedCoins: ['USDT.TRC20', 'USDT.BEP20'],
    merchantReference: orderId,           // votre identifiant interne
    returnUrl: `https://shop.example/orders/${orderId}/done`,
    // Stocké tel quel, renvoyé sur les webhooks — utile pour corréler.
    metadata: { orderId, userId: req.user.id },
  });

  // Stockez `intent.id` lié à votre commande pour retrouver la commande
  // quand le webhook arrivera.
  await db.orders.update({ id: orderId, izipayIntentId: intent.id });

  // Redirigez vers le widget de paiement.
  res.redirect(intent.paymentUrl);
}
Idempotency : si vous appelez create() deux fois avec le même idempotencyKey (auto-généré par le SDK ou passé explicitement), vous récupérez le même intent, pas de doublon.

4. Le client paye

Le client est sur la page de paiement (intent.paymentUrl) :
  1. Sélectionne sa crypto + le réseau
  2. Saisit prénom, nom, email (obligatoires) + adresse de remboursement (facultatif)
  3. Voit l’adresse de dépôt + le QR code + le montant exact à envoyer + un timer
  4. Envoie les fonds depuis son wallet
À la première confirmation on-chain, l’intent passe en confirming. Dès que le réseau confirme la transaction, il passe en completed (ou en irregular si le montant est hors plage configurée).

5. Recevoir le webhook

Quand l’intent atteint completed, IzichangePay envoie un POST signé à votre endpoint.
import express from 'express';
import { IziPayClient } from 'izichangepay-sdk';
import { izipay } from './lib/izipay';

const app = express();

// IMPORTANT: le body brut est requis pour vérifier la signature.
app.post(
  '/webhooks/izipay',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    let event;
    try {
      event = IziPayClient.validateWebhook(
        req.body,
        req.headers['x-izipay-signature'] as string,
        process.env.IZIPAY_WEBHOOK_SECRET!,
      );
    } catch (err) {
      return res.status(400).json({ error: (err as Error).message });
    }

    switch (event.type) {
      case 'payment_intent.completed': {
        const { intentId, merchantReference } = event.data as {
          intentId: string; merchantReference?: string;
        };
        // Idempotence côté receveur : pré-check dans votre DB.
        await db.orders.markPaidIfPending(merchantReference, intentId);
        break;
      }
      case 'payment_intent.expired': {
        // ...
        break;
      }
    }

    // Acquittement rapide — IzichangePay retentera si vous renvoyez 5xx.
    res.json({ received: true });
  },
);

app.listen(3000);

6. Tester de bout en bout

  1. Côté dashboard, Développeurs → Webhooks → ⋯ → Envoyer un événement test. Vérifiez que votre endpoint répond 200 et que validateWebhook() ne lance pas.
  2. En mode test, créez un intent depuis un client REST (curl ou Postman) et payez depuis un wallet sur le testnet de la crypto choisie.
  3. Vérifiez les logs côté serveur ET côté dashboard (chaque appel webhook est tracé : statut HTTP, durée, body de réponse).

Erreurs courantes

SymptômeCauseFix
IziPayWebhookError: missing_signatureLe proxy entre le client et votre serveur supprime les headersConfigurer le proxy pour préserver X-IziPay-*
IziPayWebhookError: invalid_signatureBody JSON parsé puis re-stringifié (les espaces diffèrent)Utilisez le body brut (Buffer/string), pas l’objet parsé
IziPayWebhookError: expired_timestampVotre horloge serveur est désynchroniséeVérifiez NTP / le décalage avec date -u
L’événement n’arrive jamaisEndpoint marqué failing après 5 échecs consécutifsAllez dans Webhooks → réactivez après avoir fixé votre serveur

Prochaine étape