Paiement (Payin)
Objectif
L’endpoint POST /v1/payin/sessions permet à un marchand de créer une session de paiement sécurisée entre son système et la plateforme de paiement. Cette session correspond à une intention de paiement : elle ne débite pas encore le client tant que celui-ci n’a pas confirmé ou validé la transaction
Détails de la Requête
| Élément | Description |
|---|---|
| Méthode | POST |
| Endpoint | /v1/payin/sessions |
| Auth | ✅ Authorization: Basic base64(api_key:api_client) |
| Idempotence | ✅ X-Idempotency-Key obligatoire pour éviter les doublons |
| Payload Type | application/json |
| Timeout recommandé | 30 secondes maximum |
Paramètres de la Requête
| Champ | Type | Description | Obligatoire |
|---|---|---|---|
reference | string | Identifiant unique de la transaction côté marchand (UUID recommandé). | ✅ |
accountId | string | Identifiant du compte ou du sous-compte marchand à débiter/créditer. | ✅ |
amount | number | Montant à payer (en unités entières, sans décimales). | ✅ |
msisdn | string | Numéro de téléphone du client payeur (format E.164). | ✅ |
customerName | string | Nom du client initiant le paiement. | ✅ |
country | string | Code ISO du pays (CI, SN, TG, etc.). | ✅ |
Exemple de Requête
{
"reference": "{{$randomUUID}}",
"accountId": "merchant_9923lkdz",
"amount": 300,
"msisdn": "+2250702968786",
"customerName": "John Doe",
"country": "CI"
}Exemple de Réponse
{
"type": "payin",
"fee": 6,
"reference": "tr_fhchi842jyimwiugjgszcxvb8n",
"phoneNumber": "+2250749929598",
"amount": 300,
"chargedAmount": 306,
"status": "processing",
"currency": "XOF",
"customerReference": "ef76fb64-af0b-4c37-8729-bf61d85721fd",
"confirmationRequired": true,
"confirmationStatus": "none",
"paymentUrl": "https://link.novasend.app/link/{shortCode}",
"createdAt": "2025-08-22T01:34:48.189Z"
}Interprétation de la Réponse
| Champ | Description |
|---|---|
| type | Type d’opération — ici "payin", pour un paiement entrant. |
| fee | Frais de service appliqués à la transaction. |
| reference | Référence système de la transaction côté API. |
| phoneNumber | Numéro du client payeur. |
| amount | Montant brut du paiement. |
| chargedAmount | Montant total débité (montant + frais). |
| status | Statut initial du paiement (processing, processed, expired, etc.). |
| currency | Devise utilisée, ex. "XOF". |
| customerReference | Identifiant de la requête généré ou transmis par le marchand. |
| confirmationRequired | Indique si le client doit confirmer le paiement avant exécution. |
| confirmationStatus | État de la confirmation client (voir tableau ci-dessous). |
| paymentUrl | Lien web (deep link) permettant au client de confirmer le paiement via une interface mobile ou web. |
| createdAt | Date de création de la session. |
Les attributs confirmationRequired et confirmationStatus
confirmationRequired
- Type :
boolean - Valeurs possibles :
true→ le client doit confirmer le paiement (ex. saisie OTP, approbation dans son wallet mobile, ou clic sur lien sécurisé).false→ le paiement est automatiquement validé (cas des transferts internes ou paiements instantanés).
- Rôle :
Permet au marchand de savoir s’il doit attendre une action client avant de considérer le paiement comme complété.
Exemple :
- Si
confirmationRequired = true, le système envoie un lien de validation (paymentUrl) au client. - Le paiement passe alors en statut “processing” jusqu’à la réponse du client.
- Si
confirmationStatus
-
Type :
string -
Valeurs possibles :
Valeur Description noneAucun retour du client (statut initial). acceptedLe client a confirmé le paiement (OTP validé, ou clic “Accepter”). declinedLe client a explicitement refusé le paiement. expiredDélai de confirmation dépassé (timeout). -
Rôle : Donne l’état actuel du processus de validation client. Ce statut évolue dynamiquement selon les actions du client et peut être suivi via :
- Webhook (
payin.confirmed,payin.declined) - Ou via une requête
GET /v1/payin/{reference}.
- Webhook (
Cycle de Vie d’un Paiement avec Confirmation
Bonnes Pratiques
- Toujours stocker
referenceetcustomerReferencepour pouvoir suivre la transaction. - Afficher au client le lien
paymentUrlpour validation siconfirmationRequired = true. - Utiliser le webhook pour obtenir les statuts en temps réel plutôt qu’un polling intensif.
- Si
confirmationStatus = declinedouexpired, le paiement doit être considéré comme non valide.
Statut d’un paiement
Objectif
Cet endpoint permet de consulter à tout moment l’état d’un paiement initié via l’API Marchand.
Il est particulièrement utile pour :
- Vérifier la confirmation client (acceptée ou refusée).
- Obtenir le statut final du paiement (succès, échec, en attente).
- Accéder aux informations enrichies sur la transaction traitée par le Core System (dans le champ
transaction).
Détails de la Requête
| Élément | Description |
|---|---|
| Méthode | GET |
| Endpoint | /v1/payin/{reference} |
| Auth | ✅ Requiert l’en-tête Authorization: Basic base64(api_key:api_client) |
| Paramètre | reference → identifiant unique du paiement (généré lors du POST /v1/payin/sessions) |
| Payload | Aucun |
| Taux de rafraîchissement recommandé | 1 appel toutes les 5 à 10 secondes max si polling automatique |
Fonctionnement
Lorsqu’un marchand initie un paiement (POST /v1/payin/sessions), l’API renvoie un statut initial processing ou processed.
Le paiement passe ensuite par plusieurs étapes internes :
| Étape | Description |
|---|---|
| processing | Confirmation en cours ou validation technique |
| processed | Paiement validé par le client (Mais ne défini pas le statut final de la transaction) |
| expired | Délai de confirmation dépassé |
Ce endpoint permet donc de consulter la progression complète d’un paiement à partir de sa reference.
Exemple de Réponse
{
"type": "payin",
"fee": 6,
"reference": "mtr_fhscgaywizujwjyymlge1hncaq",
"phoneNumber": "+2250749929598",
"customerName": "Habib",
"amount": 300,
"chargedAmount": 306,
"status": "processed",
"currency": "XOF",
"customerReference": "55a4e677-5700-4ed0-9a2a-9300db894ddb",
"confirmationRequired": true,
"confirmationStatus": "none",
"createdAt": "2025-08-22T02:00:16.026Z",
"transaction": {
"reference": "tr_dkjd5ljficphlqmt",
"status": "completed",
"customerName": "dd soûl",
"processedAt": "2025-11-05T16:12:42.096Z",
"phoneNumber": "+2250153013761",
"amount": "153.00",
"fees": "0.00",
"chargedAmount": "153.00",
"currency": "XOF"
},
"failure": null
}Interprétation de la Réponse
| Clé | Description |
|---|---|
| type | Type d’opération (payin) |
| fee | Montant des frais appliqués |
| reference | Référence interne du paiement |
| phoneNumber | Numéro du client ayant effectué le paiement |
| customerName | Nom associé au compte payeur |
| amount | Montant initial du paiement |
| chargedAmount | Montant total débité (montant + frais) |
| status | Statut global du paiement (processing, processed) |
| currency | Devise de la transaction (XOF, USD, etc.) |
| customerReference | Référence d’origine fournie par le marchand |
| confirmationRequired | Indique si le client doit confirmer (OTP, validation mobile, etc.) |
| confirmationStatus | État actuel de la confirmation (none, pending, accepted, declined) |
| createdAt | Date de création de la session de paiement |
| failure | Détails d’erreur en cas d’échec (null si succès) |
Clé transaction
Le champ transaction représente la transaction finale enregistrée dans le Core System une fois le paiement validé ou rejeté.
| Clé | Description |
|---|---|
| transaction.reference | Identifiant interne du Core System |
| transaction.status | Statut réel du traitement (completed, failed, pending) |
| transaction.customerName | Nom du titulaire du compte débité |
| transaction.phoneNumber | Numéro du compte ayant effectué l’opération |
| transaction.amount | Montant effectivement traité |
| transaction.fees | Frais appliqués au niveau du processeur |
| transaction.chargedAmount | Montant total débité |
| transaction.currency | Devise utilisée |
| transaction.processedAt | Timestamp exact de traitement final |
Exemple de Lecture
- Si
status = "processed"ettransaction.status = "completed"→ ✅ Paiement réussi et confirmé. - Si
status = "processed"maistransaction.status = "failed"→ ⚠️ Paiement enregistré mais refusé par le client. - Si
transactionestnullou{}dans ce cas là, le paiement n’a pas encore été confirmé par le client. - Si
failurecontient un objet → des informations d’erreur seront présentes (code,message, etc.).
Bonnes Pratiques
- Toujours stocker la
referenceet lacustomerReferencepour corrélation. - En cas de doute sur l’état, privilégier le webhook plutôt que du polling intensif.
- Le champ
transaction.statusest la source de vérité finale côté système de règlement.