SDKs mobiles
Une interface de paiement native pour les applications Flutter, React Native, Android et iOS.
Les SDKs mobiles de Wajub vous permettent d'encaisser des paiements Mobile Money, par carte et par portefeuille dans votre application, avec une interface de paiement prête à l'emploi. Choisissez ci-dessous le package de votre plateforme.
Choisir votre plateforme
| Plateforme | Package | Version | Version minimale | Ouvrir l'interface avec |
|---|---|---|---|---|
| Flutter | wajub_mobile, sur pub.dev | 1.1.1 | Flutter 3.24 | presentWajubCheckout(context, options) |
| React Native | @wajub/react-native, sur npm | 1.1.1 | React Native 0.74, React 18 | usePayment().present(options) |
| Android | com.wajub:wajub-mobile-compose, sur Maven Central | 1.2.1 | Android 7.0, API 24 | PaymentSheet(options) { result -> } |
| iOS | WajubMobileUI, avec Swift Package Manager | 1.0.0 | iOS 15 | WajubCheckout.present(options, from:) |
Pages associées
L'interface propose le Mobile Money, la carte et les portefeuilles en un geste. Les autres moyens de paiement, comme le virement bancaire ou la crypto, n'y sont pas proposés.
Le parcours d'un paiement
Your server Your app
─────────── ────────
POST /payments with sk.
returns authorization_token ──▶ present({ sessionToken })
│
├─ the payer picks a method and pays
├─ approval, confirmation step or payment page
└─ the sheet waits for the outcome
│
complete · processing · failed · cancelled
webhook payment.succeeded
fulfils the orderLe jeton est le seul identifiant détenu par l'application. Il est limité à un paiement, expire et ne permet pas de lister, de rembourser ou de lire quoi que ce soit d'autre sur votre compte. Votre clé secrète reste sur votre serveur.
Le webhook reste responsable de la livraison de la commande
Le résultat que reçoit l'application est ce que le payeur a vu, pas une preuve de paiement. Une
approbation Mobile Money peut arriver après la fermeture de l'application, et un téléphone peut
perdre le réseau pendant l'approbation. Utilisez le résultat pour choisir l'écran suivant, puis
confirmez avec GET /payments/{id} ou le
webhook payment.succeeded avant de livrer.
États
Chaque état est un écran de l'interface, et votre callback onStateChange reçoit son nom.
| État | Ce que voit le payeur |
|---|---|
INITIATED | La liste des moyens de paiement |
COLLECTING_DETAILS | Le formulaire du moyen choisi |
PROCESSING | Le formulaire, son bouton Payer occupé, ou l'écran du code de paiement pendant l'envoi du code |
APPROVAL_REQUIRED | « Validez le paiement sur votre téléphone » |
USSD_REQUIRED | « Composez ce code » |
PAYER_OTP_REQUIRED | « Générez votre code de paiement » : les étapes, le code à composer, le montant exact à saisir et un champ pour le code. Flutter, React Native et Android |
OTP_REQUIRED, PIN_REQUIRED, PHONE_REQUIRED, BIRTHDAY_REQUIRED, ADDRESS_REQUIRED | Une étape de confirmation |
3DS_REQUIRED | Le 3-D Secure dans le navigateur, ou en sandbox un code envoyé par e-mail |
VERIFYING | L'écran de l'étape pendant la vérification de sa réponse |
PENDING | « Paiement en cours », avec Continuer le paiement quand une page de paiement peut être rouverte |
SUCCESS | L'écran de succès : montant, marchand, référence et lien vers le reçu |
FAILED | L'écran d'échec, avec Réessayer quand l'erreur le permet |
EXPIRED | « Ce paiement a expiré » |
CANCELLED | « Paiement annulé » |
SUCCESS, EXPIRED et CANCELLED sont définitifs. Un paiement déjà payé à l'ouverture de
l'interface affiche l'écran de succès, et un paiement terminé affiche un avis et signale une
erreur de chargement.
Résultats
L'appel qui présente l'interface se résout une seule fois, à sa fermeture, avec l'un de quatre résultats.
| Résultat | Quand | Que faire |
|---|---|---|
complete | L'interface s'est fermée après l'écran de succès, qui se ferme seul après 3 secondes sauf indication contraire de autoCloseSuccess | Confirmer sur votre serveur, puis livrer |
processing | L'interface s'est fermée pendant un paiement en cours. L'argent peut encore bouger | Afficher un écran d'attente : votre serveur apprend l'issue par webhook |
failed | L'interface s'est fermée sur un échec, un paiement expiré, une erreur de chargement, ou un paiement annulé ailleurs | Afficher le message de l'erreur |
cancelled | Le payeur a touché Annuler le paiement (payer_cancelled), a fermé l'interface avant de payer (dismissed), ou l'écran qui l'a présentée a disparu avant (host_gone) | Créer un nouveau paiement pour le prochain essai |
L'appel ne reste jamais en suspens. Quand l'écran qui a présenté l'interface disparaît, il se
résout en cancelled avant tout paiement, en processing dès qu'un paiement a commencé et en
complete après un succès, et il n'annule pas le paiement. Présenter une deuxième interface
pendant qu'une autre est ouverte échoue avec sheet_already_presented. Si le système tue votre
application, rien ne se résout : au lancement suivant, lisez l'issue sur votre serveur.
Annuler et fermer
Le payeur ferme l'interface avec son bouton de fermeture ou d'un balayage.
| Le payeur | Résultat | Le paiement |
|---|---|---|
| Touche Annuler le paiement | cancelled, payer_cancelled | Annulé |
| Ferme l'interface avant de payer, sur l'écran du code de paiement, ou de retour sur le formulaire après un refus | cancelled, dismissed | Annulé, sauf si cancelOnDismiss vaut false |
| La ferme sur l'écran d'échec | failed, avec l'erreur que le payeur a vue | Annulé s'il peut encore l'être, sauf si cancelOnDismiss vaut false |
| La ferme pendant un paiement en cours : approbation sur le téléphone, code à composer, étape de confirmation ou attente | processing | Continue : confirmez sur votre serveur |
| La ferme après l'écran de succès | complete | Payé |
Un paiement annulé l'est pour de bon, et Wajub envoie le webhook payment.cancelled. Avec
cancelOnDismiss: false, fermer avant de payer laisse le paiement ouvert : vous pouvez présenter
l'interface à nouveau avec le même jeton.
L'interface n'affiche jamais un échec dont elle n'est pas sûre : elle affiche « Paiement en cours »
et continue d'attendre. Fermée à ce moment, elle se résout en processing.
Mobile Money
Un seul formulaire couvre tous les opérateurs. Le payeur choisit le pays et l'opérateur et saisit le numéro, mis en forme pendant la saisie. Le préfixe du numéro présélectionne son opérateur, et un numéro qui appartient à un autre opérateur est signalé avant tout envoi. Après Payer, l'interface demande au payeur de valider le paiement sur son téléphone, ou de composer un code, et attend l'issue.
Certains opérateurs, comme Orange Money au Burkina Faso, n'acceptent un paiement qu'avec un code que le payeur génère d'abord dans le menu de l'opérateur. Sur Flutter, React Native et Android, le formulaire le signale quand Wajub le sait à l'avance ; dans tous les cas, après Payer, l'interface montre comment obtenir le code, le code à composer et le montant exact à saisir, puis prend le code. Un code que l'opérateur refuse peut être saisi de nouveau, avec les essais restants quand ils sont connus ; après trois refus, le payeur revient au formulaire pour payer autrement.
Partout où l'interface affiche un montant, sur Payer et sur chaque écran, c'est ce que paie le
payeur : le montant du paiement, plus les frais Wajub quand le payeur les supporte
(bearer: customer). Sur Flutter, React Native et Android, il suit le moyen ou l'opérateur que le
payeur choisit.
Option mobileMoney | Effet |
|---|---|
country | Le pays de départ, en ISO-2. Sans elle, le pays du payeur quand il est proposé |
countryLocked | Masque le sélecteur de pays |
operatorMode | choose liste les opérateurs (par défaut). detect affiche l'opérateur détecté comme un badge dans le champ du numéro |
Cartes
Selon le paiement, le payeur paie par carte à l'un de ces trois endroits.
- Le formulaire de carte de Stripe, dans l'interface. Intégré aux SDKs Flutter et Android.
React Native a besoin du package facultatif
@stripe/stripe-react-native, et sur iOS votre application fournit unCardCollectorconstruit avec le SDK de Stripe. Chaque page de plateforme indique quoi ajouter. - Une page sécurisée du prestataire de paiement, ouverte dans le navigateur. Donnez à
returnUrlun lien universel ou un lien d'applicationhttpsvers votre application pour y ramener le payeur. Sans lui, le payeur revient dans votre application de lui-même, et Continuer le paiement rouvre la page. - Le formulaire de carte de test de Wajub, en sandbox.
En live, le numéro de carte n'est saisi que dans le formulaire de Stripe ou sur la page du prestataire.
Étapes de confirmation
Certains paiements par carte demandent une information de plus au payeur après Payer. Chaque étape a son propre écran.
| État | Le payeur saisit |
|---|---|
OTP_REQUIRED | Le code qu'il a reçu |
PIN_REQUIRED | Le code PIN de la carte |
PHONE_REQUIRED | Un numéro de téléphone |
BIRTHDAY_REQUIRED | Une date de naissance |
ADDRESS_REQUIRED | Une adresse de facturation |
3DS_REQUIRED | Le 3-D Secure dans le navigateur, ou en sandbox le code envoyé par e-mail |
Une mauvaise réponse garde l'écran et affiche les tentatives restantes. Une étape qui expire ou épuise ses tentatives se termine sur l'écran d'échec.
Apparence
L'option appearance règle l'aspect de l'interface. Ses clés, préréglages et variables sont
décrits dans Apparence.
- Mode de couleur.
light,darkouauto, qui suit le téléphone. - Préréglages.
stripe,night,flatetnone. - Le thème de votre application.
inherit: truereprend les couleurs de votre application ; chaque page de plateforme indique ce qu'il lit. - Branding du marchand. Ce que vous laissez vide vient du branding du marchand dans le Dashboard : logo, nom commercial et couleurs. Un marchand en marque blanche masque « Sécurisé par Wajub ».
- Polices. Une
fontFamilyn'est utilisée que si votre application embarque la police. - Chargement.
loaderest un squelette ou un indicateur de chargement.readyTimeout, 15 secondes par défaut, est le temps de chargement accordé à l'interface avant qu'elle affiche une erreur avec Réessayer.
Erreurs
Chaque échec est une WajubError.
| Champ | Usage |
|---|---|
type | api_error, authentication_error, invalid_request_error, payment_error ou rate_limit_error |
code | L'un des codes ci-dessous |
message | Pour le payeur, dans la langue de l'interface. Affichez-le tel quel |
declineCode | Sur un refus, le code de la banque ou de l'opérateur |
retryable | Si un nouvel essai peut aboutir |
param | Le champ en cause |
correlationId | L'identifiant de requête à citer au support de Wajub |
retryAfterSeconds | Sur rate_limited, le temps d'attente |
blockReference | Sur shield_blocked, la référence à citer au support de Wajub |
React Native écrit ces champs en snake_case : decline_code, correlation_id,
retry_after_seconds, block_reference.
| Groupe | Codes | Arrive dans |
|---|---|---|
| Chargement | session_not_found, session_terminal_expired, session_terminal_cancelled, session_terminal_failed, load_error et ready_timeout (nouvel essai possible), no_payment_method | onLoadError, puis le résultat failed |
| Connexion | network_error, timeout, server_error, rate_limited, request_failed | onError |
| Paiement | payment_declined, insufficient_funds et les autres codes de refus (nouvel essai possible), payment_attempt_ended (nouvel essai possible, rien n'a été débité), payment_failed, payment_cancelled, session_expired, limit_exceeded, shield_blocked, merchant_not_verified, merchant_restricted, payment_method_restricted, country_restricted, currency_restricted, channel_not_accepted, unsupported_action, redirect_unavailable | onError |
| Étapes de confirmation | invalid_otp, invalid_pin, invalid_phone, invalid_birthday, invalid_address, invalid_code (l'écran reste), otp_expired, pin_expired, phone_expired, birthday_expired, address_expired, max_attempts_exceeded, otp_attempts_exceeded (retour au formulaire), 3ds_failed, 3ds_rejected, 3ds_cancelled, 3ds_timeout | L'écran de l'étape, ou onError |
| Votre code | sheet_already_presented | L'appel qui présente l'interface |
Un code absent de cette liste, le code de refus propre à une banque par exemple, peut aussi vous
parvenir : affichez message. Les erreurs de champ, un numéro de téléphone invalide par exemple,
restent sur le formulaire et n'arrivent jamais dans onError.
Les tentatives de paiement sont limitées
Sur rate_limited, l'interface décompte retryAfterSeconds avant Réessayer. N'entourez pas
le SDK d'une boucle de nouvelles tentatives de votre côté.
Confidentialité
Les quatre SDKs, Flutter, React Native, Android et iOS, envoient les mêmes données. Quand le payeur paie, le SDK envoie à Wajub ce dont le paiement a besoin et, pour la prévention de la fraude, des informations de base sur l'appareil et un identifiant d'installation aléatoire, qui n'est pas l'identifiant publicitaire. Quand le payeur utilise le formulaire de carte de Stripe, le SDK de Stripe collecte aussi ce que Stripe documente pour ses propres contrôles antifraude.
Déclarez-le à côté de ce que votre application collecte elle-même.
Pour les étiquettes de confidentialité de l'App Store, déclarez-le lié à l'utilisateur, non utilisé pour le suivi, pour App Functionality, ce qui couvre le traitement du paiement et la prévention de la fraude.
| App Store Connect | Ce qu'envoie le SDK |
|---|---|
| Contact Info, Name | Prénom et nom, ou titulaire de la carte, quand le moyen de paiement les demande |
| Contact Info, Email Address | Quand le paiement par carte la demande |
| Contact Info, Phone Number | Le numéro Mobile Money, ou un numéro de téléphone que demande un paiement par carte |
| Contact Info, Physical Address | Adresse, ville, code postal et pays, quand le paiement par carte les demande |
| Financial Info, Payment Info | Le compte Mobile Money, le jeton de carte Stripe, un code PIN de carte quand il est demandé, et les cartes de test en sandbox |
| Identifiers, Device ID | L'identifiant d'installation aléatoire, pour la prévention de la fraude |
| Other Data | Une date de naissance quand elle est demandée, et des informations de base sur l'appareil, pour la prévention de la fraude |
Le SDK iOS embarque un manifeste de confidentialité, que Xcode intègre au rapport de confidentialité de votre application.
Pour la sécurité des données de Google Play, déclarez-le collecté pour App functionality et Fraud prevention, security, and compliance, partagé avec Wajub en tant que prestataire de paiement, chiffré en transit.
| Sécurité des données de Google Play | Ce qu'envoie le SDK |
|---|---|
| Personal info, Name | Prénom et nom, ou titulaire de la carte, quand le moyen de paiement les demande |
| Personal info, Email address | Quand le paiement par carte la demande |
| Personal info, Phone number | Le numéro Mobile Money, ou un numéro de téléphone que demande un paiement par carte |
| Personal info, Address | Adresse, ville, code postal et pays, quand le paiement par carte les demande |
| Personal info, Other info | Une date de naissance, quand elle est demandée |
| Financial info, User payment info | Le compte Mobile Money, le jeton de carte Stripe, un code PIN de carte quand il est demandé, et les cartes de test en sandbox |
| Device or other IDs | L'identifiant d'installation aléatoire et des informations de base sur l'appareil, pour la prévention de la fraude |
Tests
Un paiement que votre serveur crée avec une clé de sandbox place tout le parcours en sandbox, interface comprise, et l'interface affiche un badge « Mode test ». Rien ne change dans l'application. Les numéros et cartes de test figurent dans Scénarios de test.
Pages associées
- Créer un paiementL'appel serveur qui génère le jeton.
- Sessions et sécuritéCe qu'un jeton de session permet et ne permet pas de faire.
- WebhooksLa confirmation qui déclenche la livraison de la commande.
- ApparenceL'objet qui habille l'interface.
- Moyens de paiementTous les opérateurs, par pays.
- Choisir votre SDKLes versions minimales des environnements d'exécution et les contraintes qui excluent une option.