Paiements

Le fonctionnement des paiements

Intentions de paiement, tentatives, les statuts que traverse un paiement, et le signal auquel se fier avant de livrer.

Ouvrir en Markdown
Sur cette page
  1. Intentions de paiement et tentatives
  2. Le cycle de vie
  3. Chaque statut, et que faire
  4. Quand quelque chose ne colle pas
  5. Tentatives
  6. Actions suivantes
  7. Montants et devise
  8. Redirections et webhooks : auquel se fier
  9. Remboursements
  10. Les événements que vous recevez

Chaque paiement, par carte ou en espèces, est une intention de paiement (payment intent) : un objet pour un montant à encaisser, de sa création jusqu’à l’argent reçu. Vous la créez vous-même, ou une session de paiement ou un lien de paiement la crée pour vous. Son status dit où elle en est ; votre code le lit au lieu de le deviner.

Intentions de paiement et tentatives

Une intention de paiement peut être tentée plusieurs fois. Chaque essai est une tentative, aussi appelée charge (ch_…) : une page de paiement par carte ouverte, ou un code espèces émis. Une carte refusée ou un code expiré termine la tentative, pas l’intention de paiement : votre client peut réessayer, avec le même moyen ou un autre.

  • Le latest_charge de l’intention nomme sa tentative la plus récente.
  • Une intention de paiement réussit une seule fois. Même si une confirmation nous parvient plusieurs fois, il y a un seul succès, un seul événement payment_intent.succeeded et une seule écriture dans votre solde.
  • amount_received est fixé quand le paiement réussit ; amount_refunded augmente à chaque remboursement.

Le cycle de vie

Les statuts d’une intention de paiement
  • requires_payment_method → requires_action: page carte ou code espèces
  • requires_action → processing: client a payé
  • processing → succeeded: confirmé, montant exact
  • requires_action → requires_payment_method: refusé, échoué ou expiré
  • processing → requires_payment_method
  • requires_payment_method → canceled: annulé ou expiré
  • requires_action → canceled: vous annulez

Un paiement par carte confirmé tout de suite peut aussi passer directement de requires_action à succeeded.

Chaque statut, et que faire

StatutCe qu’il signifieCe que vous faites
requires_payment_methodRien n’est en cours de paiement : le paiement vient d’être créé, ou la dernière tentative a échoué.Envoyez votre client payer, ou laissez-le réessayer. last_payment_error dit pourquoi la dernière tentative a échoué.
requires_actionVotre client doit agir : terminer sur la page de paiement par carte, ou payer le code espèces chez un agent.Attendez. Avec votre propre page, affichez next_action (voir plus bas).
processingVotre client a payé ; la confirmation est en route.Attendez le webhook. Ne livrez pas encore.
succeededLe paiement est confirmé et le montant correspond.Livrez la commande. C’est définitif.
canceledVous avez annulé le paiement, ou sa session de paiement a expiré sans paiement.Rien : aucun argent ne circule. Créez un nouveau paiement si votre client revient.

Quand quelque chose ne colle pas

Si un paiement est confirmé pour un autre montant que celui demandé, ou si de l’argent arrive après l’annulation du paiement ou l’expiration de son code, rien n’est crédité automatiquement. L’intention de paiement reste en processing et reçoit un objet review, avec reason à amount_mismatch ou paid_after_end, et vous recevez review.opened. Une personne de notre équipe l’examine. Dans le bac à sable, les scénarios espèces permettent de déclencher les deux.

Tentatives

Le status d’une tentative vaut pending, succeeded, failed, canceled ou expired. Une tentative échouée porte failure_code et failure_message, et l’intention les recopie dans last_payment_error :

CodeMoyenCe qui s’est passé
card_declinedCarteLa banque a refusé. decline_code peut préciser, par exemple insufficient_funds.
expired_cardCarteLa carte a expiré.
authentication_failedCarteLe 3-D Secure n’a pas abouti.
processing_errorCarte, espècesLe paiement n’a pas pu être traité. Votre client peut réessayer.
voucher_expiredEspècesLe code n’a pas été payé avant son échéance.
voucher_refusedEspècesLe réseau de paiement a refusé le code.

Une tentative a une durée de vie limitée : environ 30 minutes pour une page de paiement par carte, et l’échéance du code pour les espèces (environ trois jours). Une tentative arrivée à son terme finit expired.

Actions suivantes

Tant qu’une intention de paiement est en requires_action, son next_action dit ce que votre client doit faire. Avec la page hébergée ou un lien de paiement, vous ne le lisez jamais : nos pages s’en chargent. Avec votre propre page :

  • form_post, pour une carte : une adresse et des champs que le navigateur de votre client envoie pour atteindre la page de paiement par carte.
  • display_voucher, pour les espèces : le code, l’amount_to_pay (votre montant plus un petit droit de timbre payé par votre client), expires_at, un slip_url imprimable, et hosted_voucher_url, notre page du bon.

Montants et devise

  • Chaque montant est un entier en centimes : 25000 vaut 250,00 MAD. N’envoyez jamais de décimales.
  • currency vaut toujours mad, en minuscules.
  • Un paiement en espèces vaut au moins 100,00 MAD (10000) ; un paiement par carte au moins 1,00 MAD (100). Un montant inférieur est refusé avec amount_too_small, en mode test comme en production.

Redirections et webhooks : auquel se fier

Votre client revient sur votre success_url après avoir payé, mais ce retour ne prouve rien : il peut fermer l’onglet avant, un paiement en espèces se fait des jours plus tard chez un agent, et n’importe qui peut taper l’adresse.

Livrez sur l’un de ces deux signaux seulement :

  1. le webhook payment_intent.succeeded, avec une signature vérifiée ;
  2. l’intention de paiement lue dans l’API, avec votre clé secrète, qui montre status: "succeeded".

Servez-vous du retour pour remercier votre client et afficher « Nous confirmons votre paiement » ; laissez ensuite le webhook faire le reste.

Remboursements

Un paiement par carte réussi peut être remboursé, en totalité ou en partie, tant que le total remboursé ne dépasse pas le montant reçu. Un remboursement est pending, puis succeeded, failed ou canceled. Un paiement en espèces ne peut pas être remboursé par AdProMaxPay : l’argent a été remis en espèces, et il n’y a pas de carte sur laquelle le rendre. Réglez-le directement avec votre client. Voir Remboursements.

Les événements que vous recevez

ÉvénementQuand
payment_intent.requires_actionUne page carte a été ouverte ou un code espèces émis.
payment_intent.processingVotre client a payé ; la confirmation est en route.
payment_intent.succeededLe paiement est confirmé. Livrez.
payment_intent.payment_failedUne tentative a échoué : refusée, expirée ou rejetée.
payment_intent.canceledLe paiement a été annulé.
charge.succeeded, charge.failedUne tentative a réussi ou échoué.
review.openedQuelque chose ne colle pas ; rien n’a été crédité.

La liste complète est dans Webhooks.