Hosted Checkout
Avec le Hosted Checkout, vous ne choisissez pas l’opérateur : vous créez
une intention de paiement, redirigez votre client vers checkout_url, et
c’est lui qui choisit Airtel Money ou Moov Money sur la page Kadryza. Son
choix crée une Payment Session, dont vous
suivez le résultat comme d’habitude.
| Payment Session | Hosted Checkout | |
|---|---|---|
| Qui choisit l’opérateur | Vous | Votre client |
| Interface de paiement | La vôtre (ou checkout_url) | Page Kadryza |
| Résultat | Webhooks payment_session.* | Webhooks payment_session.* de la session créée |
| SDK Node.js | Pris en charge | Non pris en charge |
Créer un Hosted Checkout
/v1/hosted-checkoutsX-API-KeyPortée de clé requise : write_transactions. L’environnement est celui de la clé.
| Champ | Type | Requis | Description |
|---|---|---|---|
reference | string | Oui | Votre identifiant de commande, unique par environnement ; il sera aussi la référence de la Payment Session |
amount | integer | Oui | Montant en XAF, entier strictement positif |
currency | string | Oui | XAF |
customer_phone | string | Non | Téléphone du payeur. Pour un paiement live, s’il est absent ici, la page le demande au client |
description | string | Non | Affichée au client sur la page de paiement |
metadata | object | Non | Stockée, jamais renvoyée |
ttl_minutes | integer | Non | Validité totale, de 1 à 60 minutes (défaut 10), choix de l’opérateur compris |
return_url | string | Non | Adresse de votre site où renvoyer le client une fois le paiement réglé. URL absolue https (http://localhost accepté avec une clé de test), 2048 caractères au plus, sans identifiants. Voir Retour sur votre site |
pricing_version | integer | Non | 1 pour accepter un détail serveur avec frais client et total à payer. Requis quand la politique ajoute des frais au payeur. |
Le détail pricing, lorsqu’il est présent, est figé dès la création de
l’intention, avant le choix de l’opérateur. Une répétition de la même intention
et sa future Payment Session gardent les mêmes montants, même si le tarif
global a changé. amount retourné est le total à payer; le montant original
de commande est pricing.original_amount. Voir le contrat de tarification.
curl -X POST https://api.kadryza.app/v1/hosted-checkouts \
-H "X-API-Key: $KADRYZA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"reference": "order_2026_002",
"amount": 5000,
"currency": "XAF",
"description": "Commande #2026-002",
"return_url": "https://boutique.example/commande/2026-002"
}'{
"id": "ffd10eac-14d4-4646-a557-495784fcafb8",
"reference": "order_2026_002",
"amount": 5000,
"currency": "XAF",
"environment": "test",
"status": "OPEN",
"expires_at": "2026-06-05T12:40:00Z",
"created_at": "2026-06-05T12:30:00Z",
"checkout_url": "https://checkout.kadryza.com/pay/checkout/ffd10eac-14d4-4646-a557-495784fcafb8",
"return_url": "https://boutique.example/commande/2026-002"
}Une fois l’opérateur choisi, la réponse (et les lectures suivantes côté page)
porte selected_operator et payment_session_id.
Idempotence : recréer avec la même reference et le même contenu
(return_url compris) renvoie l’intention existante ; avec un contenu
différent, 409 IDEMPOTENCY_CONFLICT.
Retour sur votre site
Avec return_url, la page de paiement renvoie votre client chez vous une fois
le paiement réglé :
- paiement confirmé : bouton « Retour sur votre nom » et retour automatique au bout de 3 secondes, que le client peut annuler (une seule fois par paiement, recharger la page ne le relance pas) ;
- en vérification, expiré, échoué ou annulé : bouton de retour, sans redirection automatique.
Kadryza ajoute deux paramètres à votre adresse, en conservant les vôtres :
| Paramètre | Valeurs |
|---|---|
kadryza_status | succeeded, under_review, expired, failed, cancelled |
kadryza_reference | Votre reference |
https://boutique.example/commande/2026-002?kadryza_status=succeeded&kadryza_reference=order_2026_002Ces paramètres servent à afficher la bonne page, pas à livrer : n’importe
qui peut taper une adresse. Confirmez toujours le paiement par le webhook
payment_session.succeeded ou en lisant la session
(GET /v1/payment-sessions/by-reference). Le webhook arrive en général
quelques secondes après la confirmation, parfois avant le retour du client.
Statuts d’une intention
| Statut | Signification |
|---|---|
| OPEN | En attente du choix de l’opérateur |
| SELECTED | Opérateur choisi, une Payment Session existe : suivez-la |
| EXPIRED | Délai dépassé sans choix d’opérateur |
| CANCELLED | Le client a renoncé avant de choisir un opérateur |
Aucune capacité n’est réservée tant que le client n’a pas choisi : la liste des opérateurs proposés est recalculée à chaque affichage et revérifiée au moment du choix. Si aucun opérateur n’est disponible, la page l’indique au client.
Endpoints utilisés par la page de paiement
Ces endpoints sont publics et appelés par la page hébergée. Vous n’avez pas à les appeler ; ils sont décrits pour comprendre les erreurs visibles par votre client.
/v1/checkout/intents/:idPublic · sans cléVue du paiement : marchand, montant, opérateurs éligibles, session éventuelle.
/v1/checkout/intents/:id/selectPublic · sans cléChoix de l'opérateur ({ operator, customer_phone? }). Crée la Payment Session.
/v1/checkout/intents/:id/cancelPublic · sans cléRenoncement du client, uniquement avant le choix de l'opérateur.
| HTTP | code | Cause |
|---|---|---|
| 404 | NOT_FOUND | Intention inconnue |
| 409 | OPERATOR_NO_LONGER_AVAILABLE | L’opérateur n’est plus disponible au moment du choix |
| 409 | OPERATOR_SELECTION_CONFLICT | Un autre opérateur a déjà été choisi |
| 409 | CHECKOUT_CANCELLED, CHECKOUT_NOT_CANCELLABLE | Intention annulée, ou annulation après le choix |
| 410 | CHECKOUT_EXPIRED | Délai dépassé |
| 503 | OPERATOR_AVAILABILITY_UNAVAILABLE | Disponibilité des opérateurs momentanément invérifiable |
| 429 | RATE_LIMIT_EXCEEDED | Trop de tentatives |
Répéter le même choix renvoie la même session : un double clic ne crée pas deux paiements.
Suivre le résultat
Écoutez les webhooks payment_session.succeeded, payment_session.under_review
et payment_session.expired (Webhooks). Leur champ
data.reference est votre reference. En l’absence de webhook, lisez la
session avec GET /v1/payment-sessions/by-reference?reference=….
L’annulation d’une intention par le client n’émet pas de webhook. Une
intention EXPIRED ou CANCELLED n’a jamais créé de session.