Passer au contenu principal
Voici la procédure à suivre depuis votre propre application — que vous intégriez SandPay pour la première fois, que vous le réinstalliez proprement ou que vous mettiez à niveau une intégration existante vers la version courante de l’API. Elle ne présuppose aucun code préalable ; chaque étape est générique et fonctionne avec n’importe quelle stack (une application Node avec @sandpay/node, ou un client fait maison en Deno / Python / Go via HTTP brut).
SandPay est la source de vérité. Ancrez votre comportement sur ce que GET /v1/meta rapporte et sur ce que dit le Changelog d’intégration — jamais sur une hypothèse codée en dur. Ce guide reste valide à travers les versions car chaque détail spécifique à une version provient de ces deux sources.

Quel chemin prenez-vous ?

Chemin A — Mise à niveau

Vous avez déjà une intégration fonctionnelle sur une ancienne version de l’API et souhaitez passer à la version courante (adopter les remboursements/décaissements, etc.).

Chemin B — Installation / réinstallation

Vous intégrez depuis zéro, ou vous supprimez l’ancienne intégration pour la refaire proprement.

Chemin A — Mettre à niveau une intégration existante

1

Faites le point : version actuelle vs version cible

Demandez à l’instance ce qu’elle supporte. La version qu’elle rapporte est votre cible :
curl $SANDPAY_BASE_URL/api/v1/meta
# hébergé : curl https://api.sandpay.dev/v1/meta
{ "api_version": "2026-05-30", "capabilities": ["payments","refunds","disbursements","webhooks","commission_split", "..."], "min_sdk_version": "0.2.0" }
Puis lisez le Changelog d’intégration depuis votre version actuelle jusqu’à la cible — notez chaque ligne “Action requise ?”.
2

Mettez à jour le client vers ≥ min_sdk_version

  • Node : npm i @sandpay/node@latest (doit être ≥ min_sdk_version).
  • Client fait maison (Deno/Python/Go) : reproduisez manuellement les nouvelles méthodes/champs (les nouveaux endpoints + champs de réponse sont dans le changelog et le Guide d’intégration).
3

Migrez la base de données — uniquement si vous hébergez SandPay vous-même

Contre le service hébergé api.sandpay.dev : rien à faire. Si vous faites tourner votre propre instance : corepack pnpm --filter sandpay-app run db:migrate.
4

Appliquez chaque modification 'Action requise'

Faites exactement ce que les entrées du changelog indiquent. À partir de 2026-05-30, la seule qui affecte le code existant est : branchez votre handler webhook sur event (pour que les remboursements/décaissements ne soient pas confondus avec des collectes) — voir Récepteur webhook ci-dessous. Tout le reste est additif et ne nécessite aucune modification.
5

Vérifiez + redéployez

Relancez vos tests d’intégration, redéployez, puis confirmez que GET /api/v1/meta (ou l’en-tête X-SandPay-Api-Version sur n’importe quelle réponse /v1/*) rapporte la version attendue.
Le retour arrière est simple car v1 est additif : si quelque chose dysfonctionne, rétrogradez votre SDK vers la version précédente et redéployez — les anciens appels fonctionnent toujours contre la nouvelle instance. Puis retentez la mise à niveau.

Chemin B — Installer (ou réinstaller) depuis zéro

Vous réinstallez ? Supprimez d’abord les anciennes hypothèses. Si vous refaites une intégration écrite contre une ancienne version, supprimez tout code qui supposait que « SandPay ne peut pas faire de versements » ou qui traitait chaque webhook comme une collecte — les deux sont faux depuis 2026-05-30. Repartez des étapes ci-dessous.

Étape 0 — Prérequis

  • Un compte SandPay + une clé API (sp_sk_test_…).
  • Au moins un environnement opérateur configuré dans le tableau de bord (Paramètres → Pays & opérateurs), ex. MTN / RW / RWF.
  • Un secret de signature webhook (affiché dans les paramètres webhook du tableau de bord).

Étape 1 — Variables d’environnement (côté serveur uniquement)

La clé API est un secret serveur. Ne l’envoyez jamais vers un navigateur, une application mobile ou un bundle client quelconque. Tous les appels SandPay transitent par client → votre backend → SandPay.
# Supprimez tout slash final de l'URL de base.
SANDPAY_BASE_URL=https://api.sandpay.dev      # ou votre URL de tunnel/instance auto-hébergée
SANDPAY_API_KEY=sp_sk_test_xxxxxxxx
SANDPAY_WEBHOOK_SECRET=whsec_xxxxxxxx

Étape 2 — Installez le client

npm i @sandpay/node@latest
import { SandPay } from "@sandpay/node";
const sandpay = new SandPay({
  apiKey: process.env.SANDPAY_API_KEY!,
  baseUrl: process.env.SANDPAY_BASE_URL, // optionnel ; pointe vers api.sandpay.dev par défaut
});
Pas de Node ? Utilisez HTTP brut. Chaque appel utilise Authorization: Bearer $SANDPAY_API_KEY vers ${SANDPAY_BASE_URL}/api/v1/… (hébergé : /v1/…).

Étape 3 — Testez la connectivité + les capacités

curl $SANDPAY_BASE_URL/api/v1/meta
Confirmez api_version, min_sdk_version, et que capabilities liste ce que vous comptez utiliser (payments, et refunds/disbursements si vous avez besoin de versements). Détectez les fonctionnalités via cela plutôt qu’en supposant.

Étape 4 — Créez un paiement (collecte : client → marchand)

const tx = await sandpay.payments.create({
  amount: 25000, currency: "RWF",
  operator: "mtn", country: "RW",
  msisdn: "+250788000001",
  reference: "ORDER-2026-0001", // votre clé d'idempotence
});
// → { id: "TX_…", status: "PENDING" | "SUCCESS" | … }
curl -X POST $SANDPAY_BASE_URL/api/v1/payments \
  -H "Authorization: Bearer $SANDPAY_API_KEY" -H "Content-Type: application/json" \
  -d '{"amount":25000,"currency":"RWF","operator":"mtn","country":"RW","msisdn":"+250788000001","reference":"ORDER-2026-0001"}'
Persistez l’id retourné (votre provider_ref). Mappez les 11 statuts ; seul PENDING est non terminal. USER_CANCELLED est terminal (ne pollez pas indéfiniment). Voir Vocabulaire des statuts.

Étape 5 — Obtenez le statut final (polling + webhook)

const p = await sandpay.payments.get("TX_…");   // GET /v1/payments/{id}
Utilisez les deux : pollez GET /v1/payments/{id} (~toutes les 4s) comme mécanisme de repli résilient, et le webhook (ci-dessous) comme notification instantanée. Réconciliez votre grand livre marchand sur net_amount, pas sur amount (commission opérateur). Voir Commission & règlement.

Étape 6 — Récepteur webhook

Un petit endpoint sur votre backend vers lequel SandPay envoie des requêtes POST. Configurez son URL dans le tableau de bord. Il doit :
  1. Vérifier la signature HMAC en temps constant, échouer fermé si le secret est absent. L’en-tête est X-SandPay-Signature: sha256=<hex> sur le corps brut.
  2. Être déployé sans authentification JWT (l’authenticité provient de la signature).
  3. Associer la transaction par tx_id (SandPay ne renvoie pas votre reference).
  4. Se brancher sur event — c’est ce qui piège le plus souvent :
switch (payload.event) {
  case "payment.completed":      // une collecte a atteint un statut terminal
    settleOrder(payload.tx_id, payload.status, payload.net_amount);
    break;
  case "payment.refunded":       // un remboursement (payload.parent_tx_id = l'original)
    recordRefund(payload.parent_tx_id, payload.tx_id, payload.status);
    break;
  case "disbursement.completed": // un versement libre
    recordPayout(payload.tx_id, payload.status);
    break;
}
Chaque événement porte le status terminal — vérifiez-le, pas seulement le nom de l’événement. Voir Webhooks.

Étape 7 — Versements (optionnel : remboursements & décaissements)

Uniquement si capabilities les inclut (vérifiez au moment de l’exécution) :
// Rembourser tout ou partie d'une collecte SUCCESS (marchand → payeur original)
await sandpay.payments.refund("TX_…", { amount: 500 }); // omettre amount = intégral
// Versement libre à un msisdn
await sandpay.disbursements.create({ amount: 5000, currency: "RWF", operator: "mtn", country: "RW", msisdn: "+250788000001" });
Aucune commission n’est prélevée sur un versement. Voir Remboursements & décaissements.

Étape 8 — Développement local

Votre URL webhook doit être publiquement accessible, et SandPay envoie les webhooks via Inngest. Donc en local :
  • Exposez votre backend avec un tunnel stable (domaine réservé ngrok) et configurez SANDPAY_BASE_URL/l’URL webhook une seule fois. Voir la configuration du tunnel.
  • Faites tourner le serveur de développement Inngest de SandPay ou reposez-vous sur le polling (Étape 5) — voir Inngest local vs cloud.

Étape 9 — Checklist finale

  • Les variables SANDPAY_* sont dans l’environnement serveur uniquement ; l’URL de base n’a pas de slash final.
  • L’environnement opérateur est activé dans le tableau de bord.
  • Création de collecte → stocker l’id ; les 11 statuts mappés ; USER_CANCELLED terminal.
  • Statut résolu par polling + webhook ; grand livre réconcilié sur net_amount.
  • Webhook : --no-verify-jwt, HMAC en temps constant, associer par tx_id, se brancher sur event.
  • URL webhook + secret configurés dans le tableau de bord (secret identique des deux côtés).
  • Versements conditionnés aux capabilities (si utilisés).
  • Développement local : tunnel + (serveur Inngest dev ou polling).
  • GET /v1/meta rapporte la version attendue après déploiement.

Voir aussi

Guide d'intégration

La référence complète faisant autorité.

Changelog d'intégration

Ce qui a changé par version — et quoi faire.

FAQ d'intégration

Pièges courants + conseils.

Démarrage rapide

Premier paiement en 10 minutes.