Paiements
Un paiement (une payment intent) représente une somme que votre client doit vous payer. Vous le créez depuis votre serveur ; le client paie sur la page du fournisseur ; Galsen Pay confirme l’issue auprès du fournisseur et vous prévient par webhook.
Le parcours
- Votre serveur crée le paiement :
POST /v1/payment-intents. - Vous redirigez le client vers
data.nextAction.url(ou lui envoyez ce lien). - Le client paie. Le fournisseur le renvoie vers votre
successUrloucancelUrl. - Galsen Pay reçoit la confirmation du fournisseur, la vérifie, crédite votre solde et envoie
payment.succeededà votre webhook. - Vous livrez la commande à réception du webhook (ou après avoir relu le paiement).
Ne livrez jamais sur la seule redirection
L’arrivée du client sur votresuccessUrl ne prouve rien : n’importe qui peut ouvrir cette adresse. Seuls le webhook signé payment.succeeded ou la lecture GET /v1/payment-intents/{id} avec le statut SUCCEEDED font foi.Créer un paiement
POST/v1/payment-intents
payments:write. En-tête Idempotency-Key obligatoire. Alias : POST /v1/payments.| Paramètre | Type | Description |
|---|---|---|
amountrequis | entier | Montant en F CFA (unités mineures), au moins 1. |
currencyrequis | "XOF" | Seule devise acceptée. |
providerrequis | "WAVE" | "SANDBOX" | "ORANGE_MONEY" | Fournisseur. SANDBOX en mode test. |
customerfacultatif | objet | phone (format international, +221…), name, email, ou id d’un client existant. Un client est créé ou retrouvé à partir du téléphone. |
descriptionfacultatif | chaîne ≤ 255 | Texte libre, visible dans vos rapports. |
metadatafacultatif | objet plat | 30 clés au plus ([A-Za-z0-9_.-], 40 caractères), valeurs : texte (≤ 500), nombre, booléen ou null. Rendu tel quel dans les réponses et webhooks. |
successUrlfacultatif | URL https | Où le fournisseur renvoie le client après paiement. |
cancelUrlfacultatif | URL https | Où il le renvoie après abandon ou échec. |
curl -sX POST https://backend.v1.pay.galsen.tech/v1/payment-intents \
-H "Authorization: Bearer $GALSEN_SECRET_KEY" \
-H "Idempotency-Key: 5f0c7b9e-2d1a-4b8e-9c3f-7a6d5e4c3b2a" \
-H "Content-Type: application/json" \
-d '{
"amount": 25000,
"currency": "XOF",
"provider": "WAVE",
"customer": { "phone": "+221771234567", "name": "Awa Diop" },
"description": "Commande #A-1042",
"metadata": { "commande": "A-1042" },
"successUrl": "https://boutique.sn/merci",
"cancelUrl": "https://boutique.sn/panier"
}'L’objet paiement
| Champ | Type | Description |
|---|---|---|
idfacultatif | uuid | Identifiant du paiement. |
referencefacultatif | chaîne | Référence lisible GSP-XXXXXXXXXXXX. |
statusfacultatif | chaîne | Voir le tableau des statuts. |
amount, currencyfacultatif | entier, "XOF" | Montant demandé au client. |
feesfacultatif | objet | providerFee (frais du fournisseur) et galsenFee (frais Galsen Pay), selon votre grille. |
netAmountfacultatif | entier | Ce qui vous revient : amount − frais. |
nextActionfacultatif | objet | null | { type: "redirect", url } tant que le client doit payer ; null ensuite. |
clientSecretfacultatif | chaîne | Renvoyé une seule fois, à la création. Sert au statut public (ci-dessous). |
paymentIdfacultatif | uuid | null | Identifiant du paiement encaissé, une fois réussi : c’est lui qu’on rembourse. |
customerfacultatif | objet | null | { id, phone } — téléphone masqué. |
failurefacultatif | objet | null | { code, message } si le paiement a échoué. |
createdAt, expiresAt, succeededAtfacultatif | dates ISO | Création, expiration de la session, réussite. |
Statuts
| Statut | Signification |
|---|---|
CREATED | Créé, pas encore transmis au fournisseur (très bref). |
PENDING | Session ouverte chez le fournisseur : le client doit payer. |
REQUIRES_ACTION | Le client doit agir (par exemple valider sur son téléphone). |
PROCESSING | Paiement en cours de traitement chez le fournisseur. |
SUCCEEDED | Payé et confirmé par le fournisseur. Vous pouvez livrer. |
FAILED | Refusé ou échoué. Aucun argent encaissé. |
CANCELLED | Annulé par vous avant paiement. |
EXPIRED | Le client n’a pas payé à temps (30 minutes par défaut). |
PARTIALLY_REFUNDED | Réussi, puis remboursé en partie. |
REFUNDED | Réussi, puis remboursé en totalité. |
UNKNOWN | Le fournisseur n’a pas répondu : issue inconnue pour l’instant (voir ci-dessous). |
Un statut ne se change jamais par l’API : seule une réponse vérifiée du fournisseur peut rendre un paiement SUCCEEDED.
UNKNOWN : ne recréez pas le paiement
UNKNOWN signifie que le fournisseur n’a pas répondu à temps : le client a peut-être payé. Ne créez pas un second paiement. Attendez le webhook, ou relisez le paiement : Galsen Pay interroge le fournisseur et tranche dès qu’il a la réponse.Lire et lister
GET/v1/payment-intents/{id}
payments:read.GET/v1/payment-intents
payments:read. Filtres : status, provider, reference, amountMin, amountMax, createdFrom, createdTo (dates ISO), plus limit et cursor.curl -s "https://backend.v1.pay.galsen.tech/v1/payment-intents?status=SUCCEEDED&createdFrom=2026-11-01T00:00:00Z&limit=50" \
-H "Authorization: Bearer $GALSEN_SECRET_KEY"Annuler
POST/v1/payment-intents/{id}/cancel
payments:write. Ferme d’abord la session chez le fournisseur, puis passe le paiement en CANCELLED. Impossible une fois le paiement réussi : remboursez-le.Paiements encaissés
GET/v1/payments · /v1/payments/{id}
payments:read. Les paiements réussis, avec refundedAmount, refundableAmount, les frais, capturedAt et settledAt (date où les fonds deviennent disponibles). L’id d’un paiement encaissé est le paymentId de l’intention.Statut public, depuis un navigateur ou une application
Pour afficher « Paiement reçu » sur une page ou dans une application sans exposer votre clé secrète : votre serveur transmet au client l’id et le clientSecret du paiement, et le client interroge l’API avec une clé publique.
GET/v1/public/payment-intents/{id}?client_secret=pi_secret_…
gsp_…_pk_…) du même compte. Réponse : { id, status, amount, currency } uniquement.C’est un affichage de confort : la décision de livrer reste côté serveur, sur le webhook. Exemples complets dans Exemples de code.