Ce guide d’intégration décrit ce processus étape par étape:

  1. Créer une intention de paiement PaymentIntent
  2. Effectuer une tentative de paiement
  3. (Optionnel) Côté client, authentifier la tentative de paiement
  4. Côté HUB2: traitement du paiement auprès des fournisseurs
  5. Récupération du statut de l’intention de paiement PaymentIntent

Voici en détail comment procéder à ces étapes.

Créer une intention de paiement

L’objet PaymentIntent est utilisé pour représenter l’intention de collecter un paiement auprès d’un client. Il conserve une trace des frais et des différentes tentatives de paiement tout au long du traitement.

L’intention de paiement PaymentIntent doit être créée sur le serveur du marchand avec un amount, une currency, la référence du client final et la référence de l’achat.

Créer une intention de paiement

curl --location --request POST 'https://api.hub2.io/payment-intents' \
--header 'ApiKey: [REDACTED]' \
--header 'MerchantId: [REDACTED]' \
--header 'Environment: sandbox' \
--header 'Content-Type: application/json' \
--data-raw '{
    "customerReference": "Test_01",
    "purchaseReference": "Test_YYYY_MM_DD_01",
    "amount": 200,
    "currency": "XOF"
}'

Cet ID et ce jeton quelque part dans l’infrastructure du marchand, ils seront nécessaires lors des étapes suivantes.

  • L’id est la référence unique de l’intention de paiement PaymentIntent, il sera utilisé lors des tentatives de paiement
  • Le token est un JSON Web Token (JWT) qui sera utilisé pour authentifier les requêtes de paiement
{
    "id": "pi_tffiDaXyWQu203rIXhujW",
    "createdAt": "2022-07-18T06:35:25.932Z",
    "updatedAt": "2022-07-18T06:35:25.944Z",
    "merchantId": "[REDACTED]",
    "purchaseReference": "Test_YYYY_MM_DD_01",
    "customerReference": "Test_01",
    "amount": 200,
    "currency": "XOF",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbnRlbnRJZCI6InBpX3RmZmlEYVh5V1F1MjAzcklYaHVqVyIsIm1lcmNoYW50SWQiOiIzIiwibW9kZSI6InNhbmRib3giLCJpYXQiOjE2NTgxMjYxMjV9.1eB6ifC2ldfRw5UstnVa-bQqIdx9_IGLRdwWyXzZR4o",
    "status": "payment_required",
    "payments": [],
    "mode": "sandbox"
}

Restrictions

Lors de la création d’une intention de paiement, des vérifications sont faites sur le champ reference : aucun caractère spécial n’est permis. L’utilisation de caractères spéciaux ici produira une erreur 400 Bad Request.

Les caractères autorisés sont les lettres, les chiffres, les tirets, les caractères de soulignement, les points ou les espaces. Voici la liste sous forme d’expression régulière : A-Za-z0-9-_. .

Tentative de paiement sur une intention de paiement

Une fois l’intention de paiement (PaymentIntent) créée, il sera possible de collecter les informations de paiement des client et de faire une tentative de Payment.

Pour ce faire Payment, vous devez spécifier une paymentMethod ainsi que tout les champs requis décris dans la référence de notre api.

Tenter un paiement

Puisque ce point de terminaison ne nécessite pas de clé api privée API_KEY, la requête de paiement peut être faite directement côté client en utilisant le JWT token enregistré au préalable pour authentifier la requête.

curl --location --request POST 'https://api.hub2.io/payment-intents/pi_tffiDaXyWQu203rIXhujW/payments' \
--header 'Content-Type: application/json' \
--data-raw '{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbnRlbnRJZCI6InBpX3RmZmlEYVh5V1F1MjAzcklYaHVqVyIsIm1lcmNoYW50SWQiOiIzIiwibW9kZSI6InNhbmRib3giLCJpYXQiOjE2NTgxMjYxMjV9.1eB6ifC2ldfRw5UstnVa-bQqIdx9_IGLRdwWyXzZR4o",
    "paymentMethod": "mobile_money",
    "country": "CI",
    "provider": "orange",
    "mobileMoney": {
        "msisdn": "00000001"
    }
}'

Si la requête est en succès, un code HTTP 201 sera retourné avec le PaymentIntent dans la réponse de la requête.

Constatez que le statut est maintenant processing et que le tableau payments contient la nouvelle tentative de paiement Payment.

L’ID du paiement peut maintenant être enregistré pour identifier cette tentative de paiement dans la liste, puisque plus d’une tentative de paiement peut être effectuée pour une seule intention de paiement PaymentIntent.

{
    "id": "pi_tffiDaXyWQu203rIXhujW",
    "createdAt": "2022-07-18T06:35:25.932Z",
    "updatedAt": "2022-07-18T06:39:21.471Z",
    "merchantId": "XXXXX",
    "purchaseReference": "Test_YYYY_MM_DD_01",
    "customerReference": "Test_01",
    "amount": 200,
    "currency": "XOF",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbnRlbnRJZCI6InBpX3RmZmlEYVh5V1F1MjAzcklYaHVqVyIsIm1lcmNoYW50SWQiOiIzIiwibW9kZSI6InNhbmRib3giLCJpYXQiOjE2NTgxMjYxMjV9.1eB6ifC2ldfRw5UstnVa-bQqIdx9_IGLRdwWyXzZR4o",
    "status": "processing",
    "payments": [
        {
            "id": "pay_GBc53h6dHvuuq4vlcP6dY",
            "intentId": "pi_tffiDaXyWQu203rIXhujW",
            "createdAt": "2022-07-18T06:39:20.721Z",
            "updatedAt": "2022-07-18T06:39:21.471Z",
            "amount": 207,
            "currency": "XOF",
            "status": "created",
            "method": "mobile_money",
            "country": "CI",
            "provider": "orange",
            "number": "00000001",
            "fees": [
                {
                    "currency": "XOF",
                    "id": "fee_drJQNmGYKQAqT7oulY519",
                    "label": "payments.customer_fee",
                    "rate": 3,
                    "rateType": "percent",
                    "amount": 7
                }
            ]
        }
    ],
    "mode": "sandbox"
}

Récupérer le statut du paiement

Après une tentative de paiement, HUB2 le fournisseur et met à jour l’objet de paiement selon la réponse.

À partir de là, le statut du paiement peut être récupéré de plusieurs façons.

1. Enregistrer un webhook pour les événements de paiement (méthode recommandée)

Au lieu de faire du polling pour détecter la mise à jour du statut du PaymentIntent, il est recommandé d’utiliser les webhooks.

Veuillez regarder à la page Intégration webhooks pour voir comment les implémenter.

Souscrivez aux événements payment ou payment_intents.

En utilisant cette méthode, le serveur du marchand sera notifié dès que le Payment ou le PaymentIntent sera mis à jour.

De cette manière, l’implémentation de mécanismes de polling est inutile, les limites de flux ne sont pas subies, et une charge potentielle due à des problèmes de temps de réponse est ainsi évitée.

Aussi, en cas de trafic élevé, la charge sur les serveurs sera réduite en conséquence, tant du côté du marchand que de celui d’HUB2.

2. Polling de statut

Effectuer un polling sur le statut du paiement en utilisant le point de terminaison dédié dans l’api.

Retrieve the status payment object

Afin de prévenir toute attaque par déni de service, ce point de terminaison est limité. Des retours HTTP 429 - Too Many Requests seront effectués dans ce cas. Il faut prendre cela en considération lors de l’implémentation du polling.

Voici un exemple de requête vers ce endpoint :

curl --location --request GET 'https://api.hub2.io/payments/pay_GBc53h6dHvuuq4vlcP6dY/status' \
--header 'ApiKey: [REDACTED]' \
--header 'MerchantId: [REDACTED]' \
--header 'Environment: sandbox'

Cela va récupérer le statut d’un paiement, mais il existe aussi un point de terminaison pour récupérer le statut d’une intention de paiement si cela est nécessaire.

Retrieve a payment intent status

Important

Le polling devrait être utilisé seulement si le PaymentIntent.status est processing ou action_required. Continuer le polling lors de statut payment_required, successful ou failed peut conclure par l’adresse IP du marchand limitée ou temporairement bannie.

Dans la plupart des cas, le statut du PaymentIntent sera action_required. Ce statut indique que la tentative de paiement est en attente d’une action manuelle du client final, qui doit authentifier ou valider le paiement.

Gérer l’action utilisateur

L’objet Payment contiendra un objet nextAction qui décrit le type d’action que le client final doit effectuer.

{
    "id": "pi_tffiDaXyWQu203rIXhujW",
    "...": "...",
    "amount": 200,
    "currency": "XOF",
    "status": "action_required",
    "payments": [
        {
            "id": "pay_GBc53h6dHvuuq4vlcP6dY",
            "intentId": "pi_tffiDaXyWQu203rIXhujW",
            "amount": 207,
            "currency": "XOF",
            "status": "pending",
            "method": "mobile_money",
            "country": "CI",
            "provider": "orange",
            "number": "00000001",
            "fees": ["..."],
            "nextAction": {
                "type": "otp",
                "message": "Mode Sandbox. Entrez un numéro à 4 chiffres pour authentifier le paiement."
            }
        }
    ],
    "nextAction": {
        "type": "otp",
        "message": "Mode Sandbox. Entrez un numéro à 4 chiffres pour authentifier le paiement."
    }
}

Important

Voici la partie qui nous intéresse : "nextAction": { "type": "otp", "message": "Mode Sandbox. Entrez un numéro à 4 chiffres pour authentifier le paiement." }.

Le message nextAction.message devrait maintenant être affiché au client final pour lui indiquer les actions à entreprendre afin de valider le paiement. L’action spécifie les étapes que le client doit suivre:

  • L’action redirection fournit les informations de redirection à une page externe.
  • L’action ussd indique la procédure USSD à suivre pour valider le paiement.
  • L’action otp indique à l’utilisateur comment générer un OTP. Ce type d’action nécessite que le client saisisse le code OTP dans un champ qui sera envoyé au point de terminaison api. Veuillez noter que certains fournisseurs permettent de passer le code OTP directement dans la requête de paiement (voir champ otp dans l’objet mobileMoney).