Node.js
Le SDK serveur @wajub/node, ses ressources et les types TypeScript inclus.
@wajub/node est le client Wajub de votre serveur : avec votre clé secrète, il crée des paiements,
lit leur statut et vérifie les signatures des webhooks. Il ne s'exécute jamais dans un navigateur.
@wajub/node
Stable · GAnpm
- Version
- 2.0.0
- Runtime
- Node.js 18+, Bun, Deno, any runtime with fetch
Couvre
- Paiements
- Facturation
- Transferts
- Sync
- Shield
- Taxes
Installer
npm install @wajub/nodeIl s'utilise avec import comme avec require.
Créer le client une seule fois
Créez-le dans un module et importez ce module partout.
import { Wajub } from '@wajub/node';
if (!process.env.WAJUB_API_KEY) {
throw new Error('WAJUB_API_KEY is missing');
}
export const wajub = new Wajub({
secretKey: process.env.WAJUB_API_KEY,
webhookSecret: process.env.WAJUB_WEBHOOK_SECRET,
});Transmettez la clé vous-même
@wajub/node ne lit pas WAJUB_API_KEY dans l'environnement, et le constructeur lève une erreur
sans clé. Lisez donc vous-même la variable, comme ci-dessus. Le secret des webhooks, lui, se
rabat bien sur WAJUB_WEBHOOK_SECRET.
| Option | Fonction |
|---|---|
secretKey | Votre clé sk. ou sk_test. |
webhookSecret | Secret whsec_, uniquement nécessaire pour webhooks.constructEvent() |
fetchOptions | RequestInit fusionné avec chaque appel, pour un proxy ou un certificat de développement |
timeout | Délai d'expiration d'une requête en millisecondes, réglable aussi par appel |
Premier appel
import { wajub } from '@/lib/wajub';
const payment = await wajub.payments.create({
amount: 25000,
currency: 'XAF',
email: 'amina@example.com',
description: 'Order 4172',
reference: 'order-4172',
callback: 'https://shop.example.com/complete',
expires: { in: 60 }, // minutes before the payment expires
});
// payment.authorization_url is where the customer pays.
// payment.authorization_token is what the browser SDK mounts.Les champs de réponse conservent le snake_case de l'API. authorization_url et created_at
s'écrivent donc comme dans la référence API. Seuls les noms de méthodes utilisent le camelCase.
Les montants utilisent l'unité principale
25000 en XAF représente vingt-cinq mille francs. Une devise décimale utilise une valeur
décimale : amount: 12.5 en GHS.
Toutes les ressources du client
| Accesseur | Méthodes |
|---|---|
| wajub.global | ping, channels, countries, currencies |
| wajub.payments | create, retrieve, list, cancel, process, processSplit, listRefunds |
| wajub.customers | create, retrieve, update, delete, list, block, unblock, activate, deactivate, listTaxIds, createTaxId, deleteTaxId |
| wajub.refunds | create, retrieve, list |
| wajub.transfers | create, retrieve, list |
| wajub.beneficiaries | create, retrieve, update, delete, list |
| wajub.links | create, retrieve, update, delete, list |
| wajub.invoices | create, retrieve, update, delete, list, send, markPaid, cancel |
| wajub.accounts | create, retrieve, update, delete, list, regenerateToken |
| wajub.webhookEndpoints | create, retrieve, update, delete, list, rotateSecret |
| wajub.balance | retrieve |
| wajub.events | list, retrieve, resend |
| wajub.disputes | list, retrieve, submitEvidence, accept, close, sendMessage |
| wajub.identity | resolve, validate |
| wajub.tax | getSettings, updateSettings, rates, calculate, reports, listCodes, retrieveCode, listRegistrations, createRegistration, retrieveRegistration, updateRegistration, deleteRegistration, jurisdictions, thresholds, thresholdAlerts |
| wajub.shield | getSettings, updateSettings, stats, listBlocklist, addToBlocklist, removeFromBlocklist |
| wajub.webhooks | constructEvent |
- La vérification de signature de
webhookss'exécute en local, sans appel HTTP. Toutes les autres ressources appellent l'API REST. links,invoices,taxetshieldne fonctionnent qu'en live. Une clé sandbox reçoit403 This feature is only available in live mode.sur chacune de leurs méthodes.refundsettransfersne proposent que la création, la lecture et la liste.
Parcourir une liste paginée
list() renvoie une page, pas un tableau. Elle contient les lignes, les métadonnées et un moyen de récupérer la suivante.
const page = await wajub.payments.list({ status: 'succeeded', per_page: 50 });
// One page at a time, when you control the loop.
for (const payment of page.data) {
console.log(payment.id, payment.amount);
}
if (page.has_more) {
const next = await page.getNextPage();
}
// Or let it fetch the following pages for you.
for await (const payment of page) {
await reconcile(payment);
}page.meta contient les champs de pagination de la liste, décrits dans Pagination.
Idempotence et nouvelles tentatives
Les échecs temporaires sont réessayés pour vous. Pour qu'une création puisse aussi être répétée sans risque de votre côté, après un redémarrage ou dans une tâche réessayée, transmettez votre propre clé d'idempotence, le numéro de commande par exemple.
await wajub.payments.create(params, { idempotencyKey: `order-${orderId}` });Agir pour un compte connecté
Les marketplaces transmettent un compte connecté par appel au lieu de conserver un second client.
await wajub.payments.create(
{ amount: 25000, currency: 'XAF', email: buyer.email },
{ sync: seller.wajubAccountId },
);La configuration et les possibilités figurent dans Sync.
Webhooks
constructEvent vérifie la signature et renvoie l'événement analysé. Il nécessite le corps exact
reçu, octet par octet.
import express from 'express';
import { wajub } from './lib/wajub';
const app = express();
app.post(
'/webhooks/wajub',
express.raw({ type: 'application/json' }),
(req, res) => {
try {
const event = wajub.webhooks.constructEvent(
req.body,
req.header('x-wajub-signature')!,
req.header('x-wajub-timestamp')!,
);
if (event.event === 'payment.succeeded') {
void fulfil(event.data);
}
res.sendStatus(200);
} catch {
res.sendStatus(400);
}
},
);express.json() détruit la signature
La signature est calculée sur le corps brut, et un corps analysé puis resérialisé ne lui
correspond plus. Montez express.raw() uniquement sur
la route du webhook avant tout analyseur JSON global, ou lisez req.text() comme dans l'onglet Next.js.
Si vos horloges dérivent, constructEvent accepte la tolérance en secondes comme quatrième
argument. Consultez
Vérification de signature.
Erreurs
import {
WajubError,
WajubInvalidRequestError,
WajubRateLimitError,
} from '@wajub/node';
try {
await wajub.payments.create(params);
} catch (error) {
if (error instanceof WajubInvalidRequestError) {
return res.status(422).json({ fields: error.errors });
}
if (error instanceof WajubRateLimitError) {
return res.status(503).set('Retry-After', String(error.retryAfter ?? 5)).end();
}
if (error instanceof WajubError) {
logger.error({ code: error.code, status: error.httpStatus, raw: error.raw });
}
throw error;
}| Classe | Cause |
|---|---|
WajubAuthenticationError | 401 et 403 |
WajubInvalidRequestError | 400, 404 et 422 |
WajubPaymentError | 402 |
WajubRateLimitError | 429, avec retryAfter en secondes |
WajubApiError | Tout autre statut |
WajubConnectionError | Aucune réponse, problème réseau ou délai d'expiration |
WebhookSignatureVerificationError | Échec de vérification d'un webhook |
Toutes étendent WajubError et contiennent message, code, httpStatus, errors et raw.
La propriété s'appelle httpStatus, pas status.
TypeScript
Les types sont inclus dans le package. Aucun @types/wajub à installer ni aucune configuration à effectuer. Tout est exporté.
import type {
CreatePaymentParams,
PaymentObject,
PaymentListParams,
CustomerObject,
RefundObject,
TransferObject,
InvoiceObject,
DisputeObject,
EventObject,
WebhookEvent,
PagedResult,
RequestOptions,
WajubConfig,
} from '@wajub/node';Débiter sans la page hébergée
Lorsque vous collectez vous-même les informations du payeur, créez d'abord le paiement, puis traitez-le sur un canal.
const payment = await wajub.payments.create({
amount: 25000,
currency: 'XAF',
phone: '+237670000000',
});
const result = await wajub.payments.process(payment.id, {
channel: 'cm.mtn',
phone: '+237670000000',
});Un canal suit le format country.operator. cm.mtn désigne donc MTN Mobile Money au Cameroun. La
liste complète figure dans Mobile Money. Le client doit
encore approuver sur son téléphone. Le résultat arrive donc dans le webhook, pas dans result.
Effectuer un payout
const transfer = await wajub.transfers.create(
{
amount: 100000,
currency: 'XAF',
beneficiary: {
name: 'Amina Diallo',
channel: 'cm.mtn',
phone: '+237670000000',
},
reference: 'payout-892',
},
{ idempotencyKey: 'payout-892' },
);beneficiary accepte aussi l'identifiant ben_… d'un bénéficiaire enregistré. Préférez cette
forme dès que vous payez deux fois la même personne.
Développement local
Le SDK appelle toujours la véritable API. Une clé de sandbox rend donc l'appel sans conséquence. Pour recevoir les webhooks sur votre machine, transférez-les avec la CLI au lieu d'exposer un tunnel.
wajub listen --forward-to localhost:3000/webhooks/wajub
wajub trigger payment.succeededConsultez la CLI pour plus de détails.
Pages associées
- Wajub.jsLa partie navigateur, montée avec le jeton renvoyé par ce SDK.
- ReactProvider et composants pour un front-end Next.js.
- WebhooksTous les événements et leurs garanties de livraison.
- IdempotenceCe que protège une clé et pendant combien de temps.
- Gestion des erreursLes échecs à réessayer et ceux à afficher.
- Vue d'ensemble de la référence APILes endpoints utilisés par toutes les méthodes ci-dessus.