Aller au contenu

Paiements

Un paiement est une demande d’argent adressée à un client. Vous le créez sur votre serveur, le client paie sur la page de paiement hébergée avec Wave ou Orange Money, et Xaalis vous communique le résultat par webhook.

stateDiagram-v2
    [*] --> requires_payment_method: POST /v1/payments
    requires_payment_method --> processing: le client choisit Wave / Orange Money
    requires_payment_method --> expired: 30 min sans paiement
    processing --> succeeded: le prestataire confirme
    processing --> failed: refusé / annulé / montant différent
    succeeded --> [*]
    failed --> [*]
    expired --> [*]

succeeded, failed et expired sont des statuts finaux. Un paiement réussi peut ensuite passer en refunded par un remboursement : rien d’autre ne modifie un paiement final. Un paiement échoué ne peut pas être relancé : créez-en un nouveau (avec une nouvelle Idempotency-Key).

POST /v1/payments avec une clé secrète. Envoyez une Idempotency-Key pour qu’une nouvelle tentative ne puisse pas créer deux paiements.

Champ Obligatoire Remarques
amount oui entier en XOF, de 100 à 100 000 000. Les nombres à virgule, les chaînes et 0 sont refusés (400).
currency non uniquement "XOF" (la valeur par défaut)
description non 200 caractères au plus, affichée au client sur la page de paiement
client_reference non votre numéro de commande (100 caractères au plus), renvoyé sur le paiement et dans les webhooks
success_url, cancel_url non où la page de paiement renvoie le client une fois le paiement dans un état final — utilisez https://
customer non { phone: "+2217XXXXXXXX", name }
metadata non chaîne → chaîne, clés de 40 caractères au plus, valeurs de 500 au plus. Jamais montrées au client.
provider non "wave" ou "orange_money" : saute le choix du moyen de paiement ; next_action est prêt dans la réponse

La réponse est l’objet paiement avec status: "requires_payment_method" et une checkout_url. Redirigez le client vers cette URL.

checkout_url contient un secret client (cs=…) qui permet au navigateur de voir uniquement ce dont le client a besoin : montant, description, nom de votre entreprise, statut. Elle n’expose jamais vos frais, metadata, client_reference ni les identifiants. Traitez cette URL comme un mot de passe : ne la journalisez pas et ne l’envoyez pas à vos outils d’analyse d’audience.

Quand le client choisit un moyen de paiement :

  • Wave → next_action: { type: "redirect", url } : la page de paiement l’envoie vers Wave. Le client peut également choisir de recevoir son reçu de paiement et le suivi de commande par WhatsApp (receipt_opt_in: true).
  • Orange Money → next_action: { type: "qr_code", qrCodeBase64, deeplinks } : un QR code pour Max It / Orange Money et des liens directs vers l’application sur mobile.

Si vous avez fixé provider à la création, vous pouvez utiliser next_action vous-même au lieu de la page de paiement hébergée.

Si un client choisit Wave puis souhaite changer d’opérateur, la page hébergée lui permet de basculer vers Orange Money après expiration de la session Wave initiale. Pour éliminer tout risque de double prélèvement, le basculement depuis une session Orange Money active est strictement refusé par l’API (409 invalid_state).

Après avoir payé, le client revient sur votre success_url. Cela ne prouve rien : n’importe qui peut ouvrir cette URL. Ne livrez la commande que sur la base :

  1. du webhook payment.succeeded signé, ou
  2. d’un GET /v1/payments/{id} qui renvoie status: "succeeded" (appelé depuis votre serveur).

fee = ceil(amount × fee_bps / 10 000) + fee_fixed, plafonné à amount. Par défaut 150 points de base (1,5 %), sans partie fixe ; votre contrat peut prévoir autre chose. net = amount − fee est ce qui arrive dans available.

montant frais à 1,5 % net
100 2 98
1 001 16 985
15 000 225 14 775
  • GET /v1/payments/{id}
  • GET /v1/payments?limit=20&status=succeeded&starting_after=pay_… — du plus récent au plus ancien, limit de 1 à 100 (20 par défaut) ; has_more indique s’il faut récupérer la page suivante en passant le dernier identifiant dans starting_after.
Champ Signification
id pay_…
livemode false pour les clés de test
amount, fee, net, currency entiers en XOF
status voir le diagramme ci-dessus
provider wave, orange_money, mock (test) ou null tant que le client n’a pas choisi
checkout_url, next_action où le client paie
client_reference, description, customer, metadata ce que vous avez envoyé
failure_reason par exemple declined_or_cancelled, amount_mismatch, expired
provider_transaction_id l’identifiant de la transaction Wave / Orange Money, une fois le paiement effectué
expires_at, succeeded_at, created_at ISO 8601