Paiement (Payin)

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émentDescription
MéthodePOST
Endpoint/v1/payin/sessions
AuthAuthorization: Basic base64(api_key:api_client)
IdempotenceX-Idempotency-Key obligatoire pour éviter les doublons
Payload Typeapplication/json
Timeout recommandé30 secondes maximum

Paramètres de la Requête

ChampTypeDescriptionObligatoire
referencestringIdentifiant unique de la transaction côté marchand (UUID recommandé).
accountIdstringIdentifiant du compte ou du sous-compte marchand à débiter/créditer.
amountnumberMontant à payer (en unités entières, sans décimales).
msisdnstringNuméro de téléphone du client payeur (format E.164).
customerNamestringNom du client initiant le paiement.
countrystringCode 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

ChampDescription
typeType d’opération — ici "payin", pour un paiement entrant.
feeFrais de service appliqués à la transaction.
referenceRéférence système de la transaction côté API.
phoneNumberNuméro du client payeur.
amountMontant brut du paiement.
chargedAmountMontant total débité (montant + frais).
statusStatut initial du paiement (processing, processed, expired, etc.).
currencyDevise utilisée, ex. "XOF".
customerReferenceIdentifiant de la requête généré ou transmis par le marchand.
confirmationRequiredIndique si le client doit confirmer le paiement avant exécution.
confirmationStatusÉtat de la confirmation client (voir tableau ci-dessous).
paymentUrlLien web (deep link) permettant au client de confirmer le paiement via une interface mobile ou web.
createdAtDate 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.

confirmationStatus

  • Type : string

  • Valeurs possibles :

    ValeurDescription
    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}.

Cycle de Vie d’un Paiement avec Confirmation


Bonnes Pratiques

  • Toujours stocker reference et customerReference pour pouvoir suivre la transaction.
  • Afficher au client le lien paymentUrl pour validation si confirmationRequired = true.
  • Utiliser le webhook pour obtenir les statuts en temps réel plutôt qu’un polling intensif.
  • Si confirmationStatus = declined ou expired, 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émentDescription
MéthodeGET
Endpoint/v1/payin/{reference}
Auth✅ Requiert l’en-tête Authorization: Basic base64(api_key:api_client)
Paramètrereference → identifiant unique du paiement (généré lors du POST /v1/payin/sessions)
PayloadAucun
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 :

ÉtapeDescription
processingConfirmation en cours ou validation technique
processedPaiement validé par le client (Mais ne défini pas le statut final de la transaction)
expiredDé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
typeType d’opération (payin)
feeMontant des frais appliqués
referenceRéférence interne du paiement
phoneNumberNuméro du client ayant effectué le paiement
customerNameNom associé au compte payeur
amountMontant initial du paiement
chargedAmountMontant total débité (montant + frais)
statusStatut global du paiement (processing, processed)
currencyDevise de la transaction (XOF, USD, etc.)
customerReferenceRéférence d’origine fournie par le marchand
confirmationRequiredIndique si le client doit confirmer (OTP, validation mobile, etc.)
confirmationStatusÉtat actuel de la confirmation (none, pending, accepted, declined)
createdAtDate de création de la session de paiement
failureDé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.referenceIdentifiant interne du Core System
transaction.statusStatut réel du traitement (completed, failed, pending)
transaction.customerNameNom du titulaire du compte débité
transaction.phoneNumberNuméro du compte ayant effectué l’opération
transaction.amountMontant effectivement traité
transaction.feesFrais appliqués au niveau du processeur
transaction.chargedAmountMontant total débité
transaction.currencyDevise utilisée
transaction.processedAtTimestamp exact de traitement final

Exemple de Lecture

  • Si status = "processed" et transaction.status = "completed" → ✅ Paiement réussi et confirmé.
  • Si status = "processed" mais transaction.status = "failed" → ⚠️ Paiement enregistré mais refusé par le client.
  • Si transaction est null ou {} dans ce cas là, le paiement n’a pas encore été confirmé par le client.
  • Si failure contient un objet → des informations d’erreur seront présentes (code, message, etc.).

Bonnes Pratiques

  • Toujours stocker la reference et la customerReference pour corrélation.
  • En cas de doute sur l’état, privilégier le webhook plutôt que du polling intensif.
  • Le champ transaction.status est la source de vérité finale côté système de règlement.