SDK officiel pour Node.js (≥ 18) et environnements serverless (Vercel, AWS Lambda, Cloudflare Workers via fetch polyfill).

Installation

npm install izichangepay-sdk

Initialisation

import { IziPayClient } from 'izichangepay-sdk';

const izipay = new IziPayClient({
  apiKey: process.env.IZIPAY_API_KEY!,                  // sk_live_… ou sk_test_…
  // baseUrl: 'https://api.pay.izichange.com',          // optionnel — défaut prod
  //                                                    // sandbox: https://api.sandbox-pay.izichange.com
  // timeout: 30_000,                                    // ms, défaut 30s
  // maxRetries: 3,                                      // 5xx/429 retry attempts
  // fetch: customFetch,                                 // override (tests / non-Node)
});
L’environnement (live vs test) est dérivé du préfixe de la clé. La clé est envoyée via header Authorization: Bearer sk_….

Ressources

Payment Intents

// Création
const intent = await izipay.paymentIntents.create({
  requestedCurrencyType: 'fiat',
  currencyRequested: 'XOF',
  amountRequested: 25000,
  acceptedCoins: ['USDT.TRC20', 'USDT.BEP20'],
  merchantReference: 'order_42',
  returnUrl: 'https://shop.example/thanks',
});

// Lecture
const fetched = await izipay.paymentIntents.retrieve(intent.id);

// Liste filtrée
const page = await izipay.paymentIntents.list({
  status: 'completed', from: '2026-11-01', limit: 50,
});

// Itérateur async (gère le curseur)
for await (const i of izipay.paymentIntents.iterate({ status: 'completed' })) {
  // ...
}

Payouts

// Standard (vers adresse blockchain externe)
const payout = await izipay.payouts.create({
  assetCode: 'USDT.TRC20',
  amount: '500.00',
  destinationAddress: 'TXxxx…',
  idempotencyKey: 'monthly-payout-2026-12',
});

// Transfert interne (vers autre marchand IzichangePay)
const internal = await izipay.payouts.createInternal({
  assetCode: 'USDT.TRC20',
  amount: '50.00',
  destinationType: 'internal_email',
  destinationEmail: 'partner@example.com',
});

Invoices

const invoice = await izipay.invoices.create({
  amount: 50000,
  currency: 'XOF',
  dueDate: '2026-12-31',
  clientEmail: 'client@example.com',
  description: 'Consultation décembre',
});

await izipay.invoices.resend(invoice.id, { dueDate: '2027-01-15' });
await izipay.invoices.cancel(invoice.id);

Products

const product = await izipay.products.create({
  name: 'Formation React',
  amount: 15000,
  currency: 'XOF',
  permanentLinkSlug: 'formation-react',
});

await izipay.products.update(product.id, { isActive: false });

Vérification webhook

import express from 'express';
import { IziPayClient } from 'izichangepay-sdk';

const app = express();

app.post('/webhooks/izipay', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    const event = IziPayClient.validateWebhook(
      req.body,                                 // Buffer brut, PAS parsé en JSON
      req.headers['x-izipay-signature'] as string,
      process.env.IZIPAY_WEBHOOK_SECRET!,
    );

    switch (event.type) {
      case 'payment_intent.completed': /* ... */ break;
      case 'payout.confirmed':         /* ... */ break;
      case 'settlement.completed':     /* ... */ break;
    }
    res.json({ received: true });
  } catch (err) {
    res.status(400).json({ error: (err as Error).message });
  }
});
validateWebhook lance une IziPayWebhookError typée avec .reason :
  • missing_signature, malformed_signature, invalid_signature
  • missing_timestamp, expired_timestamp
  • invalid_body
Voir Vérification webhook pour les détails.

Idempotence

Chaque méthode create() accepte un idempotencyKey optionnel. Si vous l’omettez, le SDK en génère un automatiquement avant l’envoi, mais utiliser le vôtre est recommandé pour pouvoir retenter en cas de panne réseau sans créer deux ressources.
await izipay.payouts.create({
  assetCode: 'USDT.TRC20',
  amount: '500',
  destinationAddress: 'TXxxx…',
  idempotencyKey: 'payout-202612-monthly-salary',
});

Retries

Le SDK retry automatiquement sur 429 Too Many Requests et sur les 5xx avec :
  • Backoff exponentiel : 250ms → 500ms → 1s → 2s → 4s (capé)
  • Jitter ±20%
  • Respect du header Retry-After quand présent
  • Max 3 tentatives par défaut (maxRetries configurable)
Les 4xx (sauf 429) ne sont jamais retentés : ce sont des erreurs métier qui ne se résoudront pas en réessayant.

Erreurs

import {
  IziPayError,                  // base
  IziPayApiError,               // 4xx/5xx
  IziPayAuthError,              // 401/403
  IziPayNotFoundError,          // 404
  IziPayValidationError,        // 422
  IziPayRateLimitError,         // 429 → .retryAfter
  IziPayServerError,            // 5xx
  IziPayNetworkError,           // pas de réponse (timeout, DNS)
  IziPayWebhookError,           // signature invalide
} from 'izichangepay-sdk';
Tous descendent de IziPayError : un instanceof IziPayError attrape tout.
Le format d’erreur réel de l’API est { statusCode, message, code }. Les propriétés défensives du SDK comme .fields (détail de validation par champ) restent typiquement vides : l’API ne renvoie pas d’enveloppe de validation par champ. Pour les rejets de validation, fiez-vous au code (par exemple INSUFFICIENT_SCOPE, DASHBOARD_ONLY) plutôt qu’à .fields. Voir Errors pour les patterns de gestion et le logging recommandés.

TypeScript

Tous les types sont exportés depuis le package racine :
import type {
  PaymentIntent, PaymentIntentCreateParams,
  Payout, PayoutCreateParams,
  Invoice, Product,
  WebhookEvent, WebhookEventType,
} from 'izichangepay-sdk';

Compatibilité

RuntimeStatut
Node.js ≥ 18✅ Officiel
Node.js 16⚠️ Requiert polyfill fetch
Cloudflare Workers✅ Compatible (fetch natif)
Vercel Edge Runtime
AWS Lambda Node 18+
Deno⚠️ Non testé, devrait marcher avec import npm:
Bun

Source

Le SDK est open-source sur github.com/izichangepay/node-sdk. Issues + PRs bienvenus.