# Le fonctionnement des paiements

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

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

| Statut                    | Ce qu’il signifie                                                                                            | Ce que vous faites                                                                                                     |
| ------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `requires_payment_method` | Rien 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_action`         | Votre 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).                                              |
| `processing`              | Votre client a payé ; la confirmation est en route.                                                          | Attendez le webhook. Ne livrez pas encore.                                                                             |
| `succeeded`               | Le paiement est confirmé et le montant correspond.                                                           | Livrez la commande. C’est définitif.                                                                                   |
| `canceled`                | Vous 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](https://pay-docs.adpromax.com/fr/sandbox/cash-scenarios) 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` :

| Code                    | Moyen          | Ce qui s’est passé                                                                  |
| ----------------------- | -------------- | ----------------------------------------------------------------------------------- |
| `card_declined`         | Carte          | La banque a refusé. `decline_code` peut préciser, par exemple `insufficient_funds`. |
| `expired_card`          | Carte          | La carte a expiré.                                                                  |
| `authentication_failed` | Carte          | Le 3-D Secure n’a pas abouti.                                                       |
| `processing_error`      | Carte, espèces | Le paiement n’a pas pu être traité. Votre client peut réessayer.                    |
| `voucher_expired`       | Espèces        | Le code n’a pas été payé avant son échéance.                                        |
| `voucher_refused`       | Espèces        | Le 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](https://pay-docs.adpromax.com/fr/webhooks/signatures) ;
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](https://pay-docs.adpromax.com/fr/payments/refunds).

## Les événements que vous recevez

| Événement                           | Quand                                                 |
| ----------------------------------- | ----------------------------------------------------- |
| `payment_intent.requires_action`    | Une page carte a été ouverte ou un code espèces émis. |
| `payment_intent.processing`         | Votre client a payé ; la confirmation est en route.   |
| `payment_intent.succeeded`          | Le paiement est confirmé. Livrez.                     |
| `payment_intent.payment_failed`     | Une tentative a échoué : refusée, expirée ou rejetée. |
| `payment_intent.canceled`           | Le paiement a été annulé.                             |
| `charge.succeeded`, `charge.failed` | Une tentative a réussi ou échoué.                     |
| `review.opened`                     | Quelque chose ne colle pas ; rien n’a été crédité.    |

La liste complète est dans [Webhooks](https://pay-docs.adpromax.com/fr/webhooks).
