Passer au contenu principal
@sandpay/node est le SDK officiel TypeScript pour Node.js 20+. Il enveloppe l’API HTTP, normalise les erreurs et expose un helper de vérification des signatures webhook.
Prefer a ready-to-run starter? See Stack Builder — il génère un projet Next.js/Express/Hono avec @sandpay/node déjà câblé et vos clés pré-remplies.

Installation

npm install @sandpay/node
# ou
pnpm add @sandpay/node

Import et constructeur

import { SandPay } from "@sandpay/node";

const sp = new SandPay({
  apiKey: process.env.SANDPAY_API_KEY!,
  // baseUrl: "https://api.sandbox.sandpay.dev", // optionnel — défaut: https://api.sandpay.dev
});
OptionTypeDéfautDescription
apiKeystringRequis. Clé sp_sk_test_....
baseUrlstringhttps://api.sandpay.devURL racine de l’API. Pour pointer un environnement custom.

payments.create(input)

Crée un paiement simulé.
const tx = await sp.payments.create({
  amount: 25000,
  currency: "FCFA",
  operator: "orange",
  country: "CI",
  msisdn: "+22507123456",
  reference: "ORDER-2026-A1",
  scenario: "success", // optionnel — défaut: "success"
});
ChampTypeRequisNotes
amountnumberouiEntier positif, unité minimale (FCFA = unité entière).
currencystringouiFCFA, XOF, XAF, RWF
operatormtn/orange/moov/airtelouiVoir guides opérateurs.
countrystring (2 lettres)ouiISO-3166. CI, BJ, TG, RW.
msisdnstringouiFormat E.164 (+225…).
referencestringouiVotre référence interne (idempotence).
descriptionstringnonDescription libre (max 200 caractères).
scenarioPaymentScenariononVoir Scénarios.

payments.get(id)

const tx = await sp.payments.get("TX_8K3M9F");
Retourne le même objet Payment que create. Lève SandPayApiError avec status: 404 si l’id est inconnu.

payments.list(params?)

const page = await sp.payments.list({
  limit: 50,
  country: "CI",
  operator: "orange",
  status: "SUCCESS",
  cursor: previousPage.nextCursor ?? undefined,
});

console.log(page.data.length, page.hasMore, page.nextCursor);
ParamTypeDéfautNotes
limitnumber (1–100)50
countrystringFiltre 2 lettres.
operatorPaymentOperator
statusPaymentStatusVoir scénarios pour les 11 valeurs.
cursorstringOpaque, fourni par la page précédente.

webhooks.verify(header, payload, secret)

Vérifie la signature HMAC-SHA256 d’un webhook. Le payload doit être le corps brut, exactement comme reçu.
const ok = sp.webhooks.verify(
  req.headers["x-sandpay-signature"] as string,
  rawBody,
  process.env.SANDPAY_WEBHOOK_SECRET!,
);

Récupérer le rawBody

// app/api/webhooks/sandpay/route.ts
export async function POST(req: Request) {
  const rawBody = await req.text();
  const ok = sp.webhooks.verify(
    req.headers.get("x-sandpay-signature") ?? "",
    rawBody,
    process.env.SANDPAY_WEBHOOK_SECRET!,
  );
  if (!ok) return new Response("invalid", { status: 401 });
  const event = JSON.parse(rawBody);
  // ...
  return Response.json({ received: true });
}

webhooks.parseEvent(rawBody)

Parse un corps webhook déjà vérifié en payload typé WebhookPayload. Appeler après verify(...).
const rawBody = await req.text();
const signature = req.headers.get("x-sandpay-signature") ?? "";

if (!sp.webhooks.verify(signature, rawBody, process.env.SANDPAY_WEBHOOK_SECRET!)) {
  return new Response("invalid signature", { status: 401 });
}

const event = sp.webhooks.parseEvent(rawBody);
// event.event === "payment.completed"
// event.tx_id, event.status, event.amount, etc. — tous typés
Lève une Error si :
  • le corps n’est pas du JSON valide (Invalid JSON in webhook body),
  • le corps n’est pas un objet JSON (Webhook body must be a JSON object),
  • le nom d’événement est inconnu (Unknown webhook event: ...),
  • un champ requis est manquant ou n’a pas le bon type (Missing or invalid field: ...).
Le contrôle est volontairement minimal — il valide la forme suffisamment pour donner un typage sûr en aval. Pour une validation exhaustive, composer avec zod.

Types exportés

  • WebhookEventName — union littérale des noms d’événements ("payment.completed" aujourd’hui).
  • WebhookPayload — interface du payload renvoyé par parseEvent.

SandPayApiError

Lancée sur tout statut HTTP non-2xx.
import { SandPay, SandPayApiError } from "@sandpay/node";

try {
  await sp.payments.create({ /* ... */ });
} catch (err) {
  if (err instanceof SandPayApiError) {
    console.error(err.status, err.code, err.message, err.requestId);
    console.error(err.detail); // payload structuré éventuel (erreurs Zod par champ)
  }
}
PropriétéTypeDescription
statusnumberStatus HTTP (400, 401, 402, 404, 429, 5xx).
codestringCode machine (voir Erreurs).
messagestringTexte humain.
detailunknownPayload structuré optionnel.
requestIdstring?En-tête X-Request-Id de la réponse (utile pour le support).

Code source

Le SDK est open source : github.com/sandpay/sandpay-node. PRs bienvenues.