Paiement en ligne (Jèko Checkout)
Encaisser en ligne par API : votre serveur crée la demande, le client paie, vous êtes notifié
Vue d'ensemble
Les paiements en application utilisent le type redirect qui permet de contrôler l'expérience utilisateur dans votre application tout en redirigeant le client vers son application de paiement mobile pour finaliser le paiement.
Pour plus de détails : Create payment request (Partner API)
Comment ça marche
Votre serveur crée la demande de paiement et reçoit une redirectUrl. Vous y envoyez le client :
il paie dans son application Mobile Money, puis revient sur l'URL de succès ou d'erreur que vous
avez fournie. Le résultat définitif vous parvient par webhook.
Vous décidez donc du montant, de la référence, du moyen de paiement et des pages de retour.
Cas d'usage
- Applications mobiles natives
- Applications web avec intégration personnalisée
- Expériences de paiement contrôlées par le développeur
- Intégrations nécessitant un contrôle total du flux
Créer une demande de paiement redirect
Pour créer une demande de paiement redirect, utilisez l'endpoint avec le type redirect.
Paramètres requis
storeId: Identifiant du magasinamountCents: Montant en centimes, multiple de 100 (minimum 100)currency: Code devise (ISO 4217), généralement "XOF"reference: Référence unique du paiement (5 à 100 caractères)paymentDetails.type:"redirect"paymentDetails.data.paymentMethod: Méthode de paiement (wave, orange, mtn, moov, djamo)paymentDetails.data.successUrl: URL de redirection en cas de succès (requis)paymentDetails.data.errorUrl: URL de redirection en cas d'erreur (requis)
Contourner le checkout Jèko (encaissement direct fournisseur)
Par défaut, une demande redirect renvoie une URL de paiement hébergée qui guide le payeur jusqu'à son opérateur. Ce flux est recommandé : il absorbe pour vous les cas limites de chaque opérateur, redirections, contraintes d'interface et variations de parcours.
Si vous connaissez déjà le numéro du payeur et la méthode (paymentMethod), le mode direct l'envoie vers son fournisseur sans étape intermédiaire. Choisissez-le si vous construisez votre propre checkout et acceptez de traiter ces cas limites vous-même.
paymentDetails.data.forceProviderDirect:truepour activer ce mode ; sinon omis oufalse(flux standard).paymentDetails.data.payerPhone: numéro mobile ivoirien du payeur, indicatif 225 obligatoire (+225ou225), suivi de01,05ou07puis huit chiffres :+2250765432108ou2250765432108. Un numéro local seul (0765432108) est refusé. Obligatoire lorsqueforceProviderDirectesttrue.
Exemple de requête
curl -X POST "https://api.jeko.africa/partner_api/payment_requests" \
-H "X-API-KEY: your_api_key_here" \
-H "X-API-KEY-ID: your_api_key_id_here" \
-H "Content-Type: application/json" \
-d '{
"storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa",
"amountCents": 10000,
"currency": "XOF",
"reference": "PAY-APP-2024-001",
"paymentDetails": {
"type": "redirect",
"data": {
"paymentMethod": "wave",
"successUrl": "https://myapp.com/payment/success?reference=PAY-APP-2024-001",
"errorUrl": "https://myapp.com/payment/error?reference=PAY-APP-2024-001"
}
}
}'Réponse réussie
{
"id": "d22c81f3-ee04-4ec5-8bd2-cd8af5dabcfc",
"storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa",
"reference": "PAY-APP-2024-001",
"type": "redirect",
"paymentMethod": "wave",
"status": "pending",
"redirectUrl": "https://pay.jeko.africa/pay_request/pr/d22c81f3-ee04-4ec5-8bd2-cd8af5dabcfc",
"errorReason": null
}Redirigez le client vers l'URL du champ redirectUrl. Elle le mène ensuite à son application de paiement.
Flux de paiement
- Créer la demande : Créez une demande de paiement redirect avec vos URLs de callback
- Rediriger le client : Redirigez le client vers
redirectUrl - Redirection automatique : Jèko redirige le client vers son application de paiement mobile
- Paiement client : Le client complète le paiement dans son application
- Retour automatique : Le client est redirigé vers votre
successUrlouerrorUrl - Notification : Vous recevez également une notification via webhook
Intégration dans votre application
Exemple : Application web
async function initiatePayment(orderId, amount) {
// Créer la demande de paiement
const response = await fetch('https://api.jeko.africa/partner_api/payment_requests', {
method: 'POST',
headers: {
'X-API-KEY': 'your_api_key_here',
'X-API-KEY-ID': 'your_api_key_id_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({
storeId: '59ae202a-f583-4a15-970f-9e99bd1e0baa',
amountCents: amount,
currency: 'XOF',
reference: `ORDER-${orderId}`,
paymentDetails: {
type: 'redirect',
data: {
paymentMethod: 'wave', // ou la méthode sélectionnée par l'utilisateur
successUrl: `https://myapp.com/payment/success?order=${orderId}`,
errorUrl: `https://myapp.com/payment/error?order=${orderId}`
}
}
})
});
const paymentRequest = await response.json();
// Rediriger le client vers l'URL de redirection
window.location.href = paymentRequest.redirectUrl;
}Exemple : Application mobile (React Native)
import { Linking } from 'react-native';
async function initiatePayment(orderId, amount) {
// Créer la demande de paiement
const response = await fetch('https://api.jeko.africa/partner_api/payment_requests', {
method: 'POST',
headers: {
'X-API-KEY': 'your_api_key_here',
'X-API-KEY-ID': 'your_api_key_id_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({
storeId: '59ae202a-f583-4a15-970f-9e99bd1e0baa',
amountCents: amount,
currency: 'XOF',
reference: `ORDER-${orderId}`,
paymentDetails: {
type: 'redirect',
data: {
paymentMethod: 'wave',
successUrl: `myapp://payment/success?order=${orderId}`,
errorUrl: `myapp://payment/error?order=${orderId}`
}
}
})
});
const paymentRequest = await response.json();
// Ouvrir l'URL de redirection
Linking.openURL(paymentRequest.redirectUrl);
}Gérer les callbacks
Page de succès
// Dans votre page /payment/success
function PaymentSuccessPage() {
const params = new URLSearchParams(window.location.search);
const reference = params.get('reference');
const orderId = params.get('order');
// Vérifier le statut du paiement via l'API
useEffect(() => {
checkPaymentStatus(reference).then(status => {
if (status === 'success') {
// Mettre à jour la commande comme payée
updateOrderStatus(orderId, 'paid');
// Afficher un message de succès
showSuccessMessage('Paiement effectué avec succès !');
}
});
}, [reference, orderId]);
return <div>Paiement réussi !</div>;
}Page d'erreur
// Dans votre page /payment/error
function PaymentErrorPage() {
const params = new URLSearchParams(window.location.search);
const reference = params.get('reference');
const orderId = params.get('order');
// Vérifier le statut du paiement via l'API
useEffect(() => {
checkPaymentStatus(reference).then(status => {
if (status === 'error') {
// Afficher un message d'erreur
showErrorMessage('Le paiement a échoué. Veuillez réessayer.');
}
});
}, [reference, orderId]);
return <div>Le paiement a échoué. Veuillez réessayer.</div>;
}Vérifier le statut
Pour vérifier le statut d'une demande de paiement :
curl -X GET "https://api.jeko.africa/partner_api/payment_requests/{paymentRequestId}" \
-H "X-API-KEY: your_api_key_here" \
-H "X-API-KEY-ID: your_api_key_id_here"Réponse avec transaction réussie :
{
"id": "d22c81f3-ee04-4ec5-8bd2-cd8af5dabcfc",
"storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa",
"reference": "PAY-APP-2024-001",
"type": "redirect",
"paymentMethod": "wave",
"status": "success",
"transaction": {
"id": "txn_1234567890",
"amount": {
"amount": 10000,
"currency": "XOF"
},
"fees": {
"amount": 100,
"currency": "XOF"
},
"status": "success",
"counterpartLabel": "Customer Name",
"counterpartIdentifier": "+2250701234567",
"description": "Payment for order #12345",
"executedAt": "2024-01-15 14:30:25"
}
}Méthodes de paiement supportées
"wave": Wave Mobile Money"orange": Orange Money"mtn": MTN Mobile Money"moov": Moov Money"djamo": DJAMO
URLs de callback
Format des URLs
Les URLs de succès et d'erreur doivent être des URLs HTTPS valides. Vous pouvez inclure des paramètres de requête pour identifier la transaction :
https://myapp.com/payment/success?reference=PAY-APP-2024-001&order=12345
https://myapp.com/payment/error?reference=PAY-APP-2024-001&order=12345Deep links (applications mobiles)
Pour les applications mobiles, vous pouvez utiliser des deep links :
myapp://payment/success?reference=PAY-APP-2024-001
myapp://payment/error?reference=PAY-APP-2024-001Important : Assurez-vous que votre application est configurée pour gérer ces deep links.
Bonnes pratiques
- URLs sécurisées : Utilisez toujours HTTPS pour les URLs de callback
- Paramètres de requête : Incluez des paramètres pour identifier la transaction (référence, orderId, etc.)
- Vérification du statut : Toujours vérifier le statut du paiement via l'API après le callback
- Gestion des erreurs : Prévoyez un traitement pour chaque cas d'échec documenté
- Webhooks : Utilisez les webhooks comme source de vérité principale, les callbacks comme fallback
- Expérience utilisateur : Affichez des messages clairs sur les pages de succès et d'erreur
- Timeouts : Gérez les cas où le client ne revient pas de l'application de paiement
Cas d'usage avancés
Sélection dynamique de la méthode de paiement
Permettez à l'utilisateur de choisir sa méthode de paiement avant de créer la demande :
function PaymentMethodSelector({ orderId, amount }) {
const [selectedMethod, setSelectedMethod] = useState('wave');
const methods = ['wave', 'orange', 'mtn', 'moov', 'djamo'];
const handlePayment = async () => {
await initiatePayment(orderId, amount, selectedMethod);
};
return (
<div>
<h3>Sélectionnez votre méthode de paiement</h3>
{methods.map(method => (
<button
key={method}
onClick={() => setSelectedMethod(method)}
className={selectedMethod === method ? 'selected' : ''}
>
{method.toUpperCase()}
</button>
))}
<button onClick={handlePayment}>Payer</button>
</div>
);
}Gestion des timeouts
Si le client ne revient pas après un certain temps, vérifiez le statut :
function PaymentPage({ orderId, amount }) {
const [paymentStatus, setPaymentStatus] = useState('pending');
useEffect(() => {
// Créer la demande de paiement
initiatePayment(orderId, amount).then(paymentRequest => {
// Rediriger le client
window.location.href = paymentRequest.redirectUrl;
// Vérifier le statut toutes les 5 secondes (timeout après 5 minutes)
const interval = setInterval(async () => {
const status = await checkPaymentStatus(paymentRequest.id);
setPaymentStatus(status);
if (status !== 'pending') {
clearInterval(interval);
}
}, 5000);
// Timeout après 5 minutes
setTimeout(() => {
clearInterval(interval);
if (paymentStatus === 'pending') {
// Gérer le timeout
handlePaymentTimeout(orderId);
}
}, 300000);
});
}, [orderId, amount]);
return <div>Redirection en cours...</div>;
}Et ensuite
- Suivre un paiement : webhook ou interrogation de l'API
- Gérer les échecs : chaque erreur et quoi en faire