SDK Java
Le SDK Java de Papi (papi-api-client) fournit un client typé pour l'API de paiement Papi. Il gère la communication HTTP, la sérialisation et les classes de modèles afin que vous puissiez vous concentrer sur votre logique métier.
Installation
Le SDK est hébergé sur le dépôt de paquets Ibonia. Ajoutez le dépôt et la dépendance à votre projet.
Maven
<repositories>
<repository>
<id>ibonia-repo-group</id>
<url>https://package-repository.ibonia.com/repository/ibonia-mvn-group</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.ibonia.papi</groupId>
<artifactId>papi-api-client</artifactId>
<version>1.0.3</version>
</dependency>
</dependencies>
Gradle
repositories {
maven { url 'https://package-repository.ibonia.com/repository/ibonia-mvn-group' }
}
dependencies {
implementation 'com.ibonia.papi:papi-api-client:1.0.3'
}
Classes principales
| Classe | Package | Description |
|---|---|---|
ApiClient | com.ibonia.papi.apiclient | Client HTTP de base. À instancier une seule fois et à partager. |
PaymentLinksApi | com.ibonia.papi.apiclient.api | Méthodes pour créer des liens de paiement et les relire. |
PaymentsApi | com.ibonia.papi.apiclient.api | Méthode pour vérifier le statut d'un paiement à partir de la référence Papi. |
PaymentLinkRequest | com.ibonia.papi.apiclient.model | Corps de la requête pour créer un lien de paiement. |
PaymentLinkResponse | com.ibonia.papi.apiclient.model | Réponse retournée après la création d'un lien de paiement. |
PaymentLinkStatusResponse | com.ibonia.papi.apiclient.model | Un lien de paiement relu par référence, avec son état et l'issue du paiement. Mêmes noms de champs que PaymentResponse, sauf la référence Papi, nommée papiPaymentReference. |
PaymentResponse | com.ibonia.papi.apiclient.model | Charge envoyée par Papi à votre endpoint de notification. |
Utilisation
Créez une instance ApiClient (elle est thread-safe) et passez-la aux classes d'API dont vous avez besoin. Son chemin de base par défaut est https://app.papi.mg. Dans une application Spring, faites-le dans le constructeur afin que les instances d'API soient prêtes à l'utilisation dès la création du bean.
import com.ibonia.papi.apiclient.ApiClient;
import com.ibonia.papi.apiclient.api.PaymentLinksApi;
import com.ibonia.papi.apiclient.api.PaymentsApi;
ApiClient apiClient = new ApiClient(); // chemin de base : https://app.papi.mg
PaymentLinksApi paymentLinksApi = new PaymentLinksApi(apiClient);
PaymentsApi paymentsApi = new PaymentsApi(apiClient);
Construisez un PaymentLinkRequest via le builder fluent. Les champs amount, description, clientName et reference sont obligatoires. notificationUrl est facultatif mais fortement recommandé.
import com.ibonia.papi.apiclient.model.PaymentLinkRequest;
import java.net.URI;
PaymentLinkRequest request = new PaymentLinkRequest()
.amount(15000.0)
.description("Paiement Commande #123")
.clientName("Jean Dupont")
.reference("ORDER-123")
.payerEmail("jean.dupont@example.com")
.payerPhone("+261340000000")
.notificationUrl(new URI("https://votreapp.com/api/notifications-paiement"))
.validDuration(60); // le lien expire après 60 heures
Appelez createPaymentLink avec votre clé API (disponible dans le tableau de bord) et la requête. La méthode retourne un wrapper — appelez .getData() pour obtenir le PaymentLinkResponse.
import com.ibonia.papi.apiclient.model.PaymentLinkResponse;
PaymentLinkResponse response = paymentLinksApi
.createPaymentLink("VOTRE_CLE_API", request)
.getData();
String urlPaiement = response.getPaymentLink(); // redirigez l'utilisateur ici
String notifToken = response.getNotificationToken(); // stockez ceci pour la vérification
Redirigez le client vers urlPaiement. Après le paiement, Papi appellera votre notificationUrl avec le résultat.
Rappeler createPaymentLink avec la même reference tant que le lien est actif retourne ce même lien (même URL, même jeton) : un réessai est sans risque. La même reference avec un montant ou une devise différents lève une ApiException dont le getCode() vaut 409.
Exposez un endpoint POST qui accepte un corps PaymentResponse. Papi appelle cet endpoint après chaque tentative de paiement.
import com.ibonia.papi.apiclient.model.PaymentResponse;
@PostMapping("/api/notifications-paiement")
public ResponseEntity<?> handleNotification(
@RequestBody @Valid PaymentResponse notification) {
// Vérifiez l'authenticité avant toute action
boolean tokenOk = notifToken.equals(notification.getNotificationToken());
boolean refOk = "ORDER-123".equals(notification.getMerchantPaymentReference());
if (!tokenOk || !refOk) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
switch (notification.getPaymentStatus()) {
case SUCCESS -> handleSuccess(notification);
case FAILED -> handleFailure(notification);
case PENDING -> handlePending(notification);
}
return ResponseEntity.ok().build();
}
Une notification n'est envoyée qu'une fois. Si votre endpoint était indisponible ou si l'appel s'est perdu, interrogez Papi directement : getPaymentLink relit le lien par votre référence marchande (la reference envoyée à la création, merchantPaymentReference dans les notifications) et retourne la même issue que celle qu'aurait portée la notification.
import com.ibonia.papi.apiclient.model.PaymentLinkStatusResponse;
PaymentLinkStatusResponse lien = paymentLinksApi
.getPaymentLink("VOTRE_CLE_API", "ORDER-123")
.getData();
switch (lien.getLinkStatus()) {
case PAID -> confirmerCommande(lien.getPapiPaymentReference()); // paymentStatus vaut SUCCESS
case ACTIVE -> {} // encore payable ; paymentStatus décrit la dernière tentative
case EXPIRED, DISABLED -> reemettreUnLienOuAnnuler();
}
getPaymentLink lève une ApiException dont le getCode() vaut 404 quand aucun lien de votre boutique ne porte cette référence, et 401 quand la clé API est incorrecte.
Lorsque vous disposez déjà de la référence de Papi pour le paiement — getPaymentReference() sur une notification, ou getPapiPaymentReference() sur un lien relu —, vous pouvez interroger le paiement lui-même. Cet appel ne prend aucune clé API.
import com.ibonia.papi.apiclient.api.PaymentsApi;
import com.ibonia.papi.apiclient.model.PaymentResponse;
PaymentResponse paiement = paymentsApi
.getPaymentStatus("mvola", papiPaymentReference)
.getData();
if (paiement.getPaymentStatus() == PaymentResponse.PaymentStatusEnum.SUCCESS) {
confirmerCommande(paiement.getMerchantPaymentReference());
}
Le premier argument est le prestataire par lequel le paiement est passé, sous forme de String : "mvola", "airtel-money", "orange-money" ou "bred-card". Une référence de paiement inconnue lève une ApiException dont le getCode() vaut 400.
Champs de PaymentLinkRequest
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
amount | double | ✓ | Montant du paiement (minimum 300 MGA). |
clientName | String | ✓ | Nom complet du client. |
reference | String | ✓ | Votre identifiant unique pour ce paiement. |
description | String | ✓ | Courte description du paiement (max 255 caractères). |
notificationUrl | URI | ✗ | Endpoint qui reçoit les notifications de statut de paiement. Fortement recommandé ; sans lui, utilisez getPaymentLink pour relire l'issue. |
payerEmail | String | ✗ | Adresse e-mail du client. |
payerPhone | String | ✗ | Numéro de téléphone du client. |
successUrl | URI | ✗ | URL de redirection après un paiement réussi. |
failureUrl | URI | ✗ | URL de redirection après un paiement échoué. |
validDuration | int | ✗ | Durée de validité du lien en heures (défaut : 1). |
provider | String | ✗ | Restreindre à un fournisseur : MVOLA, AIRTEL_MONEY, ORANGE_MONEY, BRED. |
displayCurrency | String | ✗ | Devise affichée au payeur (MGA uniquement, défaut MGA). |
isTestMode | boolean | ✗ | true pour marquer la transaction comme test dans le tableau de bord. |
testReason | String | ✗ | Raison affichée dans le tableau de bord lorsque le mode test est activé. |
Champs de PaymentResponse
| Champ | Getter | Description |
|---|---|---|
paymentStatus | getPaymentStatus() | PaymentResponse.PaymentStatusEnum : SUCCESS, FAILED ou PENDING. |
paymentMethod | getPaymentMethod() | Fournisseur utilisé : MVOLA, AIRTEL_MONEY, ORANGE_MONEY, BRED. |
currency | getCurrency() | Toujours MGA. |
displayCurrency | getDisplayCurrency() | La devise que le payeur a vue sur le formulaire (toujours MGA aujourd'hui). |
amount | getAmount() | Montant payé. |
estimatedAmount | getEstimatedAmount() | Le montant exprimé en displayCurrency (égal à amount tant que seul MGA est pris en charge). |
fee | getFee() | Frais de transaction déduits. |
clientName | getClientName() | Nom du client. |
description | getDescription() | Description du paiement. |
merchantPaymentReference | getMerchantPaymentReference() | Votre reference de la requête initiale. |
notificationToken | getNotificationToken() | Token de la réponse initiale du lien — utilisé pour vérifier l'authenticité. |
paymentReference | getPaymentReference() | La référence de Papi pour ce paiement (un UUID). Passez-la à getPaymentStatus. |
message | getMessage() | Motif d'échec, s'il y en a un. |
payerEmail | getPayerEmail() | E-mail du client (si fourni). |
payerPhone | getPayerPhone() | Téléphone du client (si fourni). |
Champs de PaymentLinkStatusResponse
| Champ | Getter | Description |
|---|---|---|
linkStatus | getLinkStatus() | PaymentLinkStatusResponse.LinkStatusEnum : ACTIVE, EXPIRED, PAID ou DISABLED. PAID l'emporte sur DISABLED et EXPIRED. |
paymentStatus | getPaymentStatus() | SUCCESS, PENDING ou FAILED — les mêmes valeurs que la notification. null tant que personne n'a tenté de payer. |
paymentMethod | getPaymentMethod() | Prestataire utilisé par le payeur. null tant qu'aucune tentative n'existe. |
currency | getCurrency() | Toujours MGA. |
displayCurrency | getDisplayCurrency() | Devise affichée au payeur. |
amount | getAmount() | Montant du lien. |
clientName | getClientName() | Nom du client. |
description | getDescription() | Description du paiement. |
merchantPaymentReference | getMerchantPaymentReference() | Votre reference de la requête initiale. |
papiPaymentReference | getPapiPaymentReference() | Référence Papi de la tentative de paiement (le paymentReference de la notification). null tant qu'aucune tentative n'existe. |
notificationToken | getNotificationToken() | Jeton retourné à la création du lien. |
message | getMessage() | Motif d'échec de la tentative de paiement, s'il y en a un. |
payerEmail | getPayerEmail() | Email du client (si fourni). |
payerPhone | getPayerPhone() | Téléphone du client (si fourni). |
paymentLink | getPaymentLink() | L'URL de paiement. |
shortLink | getShortLink() | Forme courte de l'URL de paiement, si elle a été générée. |
linkCreationDateTime | getLinkCreationDateTime() | Date de création, en millisecondes epoch. |
linkExpirationDateTime | getLinkExpirationDateTime() | Date d'expiration, en millisecondes epoch. |
isTestMode | getIsTestMode() | Indique si le lien a été marqué comme test. |
Exemple complet (Spring Boot)
L'exemple ci-dessous illustre un service Spring Boot complet qui crée un lien de paiement et gère la notification de callback — le même schéma utilisé en production.
import com.ibonia.papi.apiclient.ApiClient;
import com.ibonia.papi.apiclient.api.PaymentLinksApi;
import com.ibonia.papi.apiclient.model.PaymentLinkRequest;
import com.ibonia.papi.apiclient.model.PaymentLinkResponse;
import com.ibonia.papi.apiclient.model.PaymentResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.net.URI;
@Service
public class PaymentService {
private final PaymentLinksApi paymentLinksApi;
@Value("${app.domain}")
private String appDomain;
public PaymentService() {
this.paymentLinksApi = new PaymentLinksApi(new ApiClient());
}
public String createPaymentLink(String apiKey, double amount,
String reference, String customerName,
String email, String phone) throws Exception {
PaymentLinkRequest request = new PaymentLinkRequest()
.amount(amount)
.description("Paiement " + reference)
.clientName(customerName)
.reference(reference)
.payerEmail(email)
.payerPhone(phone)
.notificationUrl(new URI(appDomain + "/api/notifications-paiement"))
.validDuration(60);
PaymentLinkResponse response = paymentLinksApi
.createPaymentLink(apiKey, request)
.getData();
// Persistez response.getNotificationToken() avec la référence de commande
// pour pouvoir le vérifier lors de la réception de la notification.
return response.getPaymentLink();
}
public void handleNotification(PaymentResponse notification) {
String storedToken = lookupNotificationToken(
notification.getMerchantPaymentReference());
if (!storedToken.equals(notification.getNotificationToken())) {
throw new SecurityException("Token de notification invalide");
}
if (notification.getPaymentStatus() == PaymentResponse.PaymentStatusEnum.SUCCESS) {
confirmOrder(notification.getMerchantPaymentReference());
}
}
// ... implémentations de lookupNotificationToken et confirmOrder
}