???? Kadryza est en version b??ta. Cr??ez votre compte gratuitement ???
Référence APITransactions

Transactions

L’API Transactions est le cœur de Kadryza. Elle vous permet d’initier des paiements Mobile Money, de consulter leur statut et de lister l’historique de vos transactions.

URL de base : https://api.kadryza.app

🔑

Toutes les requêtes nécessitent le header Authorization: Bearer <votre_clé_api>. Consultez le guide d’authentification pour plus de détails.


Cycle de vie d’une transaction

Chaque transaction passe par les statuts suivants :

                    ┌─────────────────────────────────────┐
                    │          Initiation (POST)          │
                    └──────────────┬──────────────────────┘


                          ┌────────────────┐
                          │    PENDING     │
                          │  (en attente)  │
                          └───────┬────────┘

                    ┌─────────────┼─────────────┐
                    │             │             │
                    ▼             ▼             ▼
           ┌──────────────┐ ┌──────────┐ ┌───────────┐
           │   SUCCESS    │ │  FAILED  │ │  TIMEOUT  │
           │  (confirmé)  │ │ (refusé) │ │ (expiré)  │
           └──────────────┘ └──────────┘ └───────────┘
                    │             │             │
                    ▼             ▼             ▼
              Webhook envoyé  Webhook envoyé  Webhook envoyé
          transaction.success  transaction.failed  transaction.timeout

Détail des statuts

StatutBadgeSignificationDurée
PENDINGPENDINGL’utilisateur a reçu la demande de paiement sur son téléphoneMax 5 minutes
SUCCESSSUCCESSLe paiement a été confirmé par l’utilisateurFinal
FAILEDFAILEDLe paiement a été refusé (solde insuffisant, annulation, etc.)Final
TIMEOUTTIMEOUTL’utilisateur n’a pas répondu dans les 5 minutesFinal
EXPIREDEXPIREDLa transaction a expiré côté passerelleFinal
⚠️

Les statuts SUCCESS, FAILED, TIMEOUT et EXPIRED sont finaux. Une transaction dans un de ces statuts ne changera plus jamais. Utilisez les webhooks pour être notifié de ces changements.


Initier un paiement

POST/v1/transactions

Crée une nouvelle transaction de paiement Mobile Money

Paramètres de la requête

ParamètreTypeRequisDescription
referencestringrequisRéférence unique de votre commande. Sert de clé d'idempotence — deux requêtes avec la même reference retournent la même transaction.
amountintegerrequisMontant en XAF. Entier positif, minimum 100 XAF. Pas de décimales.
currencystringrequisDevise du paiement. Seule valeur acceptée : "XAF".
operatorstringrequisOpérateur Mobile Money. Valeurs acceptées : "AIRTEL" ou "MOOV".
phone_numberstringrequisNuméro de téléphone du payeur au format international : +235XXXXXXXX (8 chiffres après le préfixe).
descriptionstringoptionnelDescription du paiement visible par le payeur. Maximum 255 caractères.

Requête

initiate-payment.js
import Kadryza from '@kadryza/sdk'
 
const kadryza = new Kadryza({
  apiKey: process.env.KADRYZA_API_KEY
})
 
const transaction = await kadryza.transactions.initiate({
  reference: 'order_2025_001',
  amount: 15000,
  currency: 'XAF',
  operator: 'AIRTEL',
  phone_number: '+23566000000',
  description: 'Abonnement mensuel Premium'
})
 
console.log(transaction.id)           // "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
console.log(transaction.internal_ref)  // "KADRYZA-A1B2C3D4"
console.log(transaction.status)        // "PENDING"

Réponse 201 Created

201 Created
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "reference": "order_2025_001",
  "internal_ref": "KADRYZA-A1B2C3D4",
  "amount": 15000,
  "currency": "XAF",
  "operator": "AIRTEL",
  "phone_number": "+23566000000",
  "description": "Abonnement mensuel Premium",
  "status": "PENDING",
  "created_at": "2025-06-15T14:30:00Z",
  "updated_at": "2025-06-15T14:30:00Z",
  "expires_at": "2025-06-15T14:35:00Z"
}

Réponses d’erreur

HTTPCodeCauseSolution
400VALIDATION_ERRORParamètres manquants ou invalidesVérifier les champs requis ci-dessus
401UNAUTHORIZEDClé API invalideVérifier le header Authorization
409DUPLICATE_REFERENCEreference déjà utiliséeVoir section Idempotence
422VALIDATION_ERRORDonnées sémantiquement incorrectesLire le champ fields de la réponse
503GATEWAY_UNAVAILABLEPasserelle Mobile Money indisponibleRéessayer dans quelques minutes
400 Bad Request — Exemple
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Paramètres de requête invalides",
    "status": 400,
    "fields": {
      "amount": "Le montant doit être un entier positif",
      "operator": "Valeurs acceptées : AIRTEL, MOOV"
    }
  }
}

Récupérer une transaction

GET/v1/transactions/:id

Récupère les détails complets d'une transaction par son UUID

Paramètres de l’URL

ParamètreTypeRequisDescription
iduuidrequisUUID de la transaction retourné lors de la création (champ "id").

Requête

get-transaction.js
import Kadryza from '@kadryza/sdk'
 
const kadryza = new Kadryza({
  apiKey: process.env.KADRYZA_API_KEY
})
 
const transaction = await kadryza.transactions.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890')
 
console.log(transaction.status)       // "SUCCESS" | "PENDING" | "FAILED" | "TIMEOUT"
console.log(transaction.amount)       // 15000
console.log(transaction.operator)     // "AIRTEL"
console.log(transaction.internal_ref) // "KADRYZA-A1B2C3D4"

Réponse 200 OK

200 OK
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "reference": "order_2025_001",
  "internal_ref": "KADRYZA-A1B2C3D4",
  "amount": 15000,
  "currency": "XAF",
  "operator": "AIRTEL",
  "phone_number": "+23566000000",
  "description": "Abonnement mensuel Premium",
  "status": "SUCCESS",
  "created_at": "2025-06-15T14:30:00Z",
  "updated_at": "2025-06-15T14:31:12Z",
  "expires_at": "2025-06-15T14:35:00Z"
}

Réponses d’erreur

HTTPCodeCauseSolution
401UNAUTHORIZEDClé API invalideVérifier le header Authorization
404NOT_FOUNDTransaction introuvableVérifier l’UUID. La transaction appartient peut-être à un autre merchant.
404 Not Found
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Transaction introuvable",
    "status": 404
  }
}

Lister les transactions

GET/v1/transactions

Liste paginée de vos transactions avec filtres optionnels

Paramètres de requête (query string)

ParamètreTypeRequisDescription
pageintegerdéfaut: 1Numéro de la page
per_pageintegerdéfaut: 20Nombre de résultats par page (max 100)
statusstringoptionnelFiltrer par statut : PENDING, SUCCESS, FAILED, TIMEOUT, EXPIRED
operatorstringoptionnelFiltrer par opérateur : AIRTEL, MOOV
fromstring (ISO 8601)optionnelDate de début (inclusif). Format : 2025-01-01T00:00:00Z
tostring (ISO 8601)optionnelDate de fin (inclusif). Format : 2025-12-31T23:59:59Z

Requête

list-transactions.js
import Kadryza from '@kadryza/sdk'
 
const kadryza = new Kadryza({
  apiKey: process.env.KADRYZA_API_KEY
})
 
// Lister toutes les transactions (page 1, 20 résultats)
const result = await kadryza.transactions.list()
 
console.log(result.data)        // Transaction[]
console.log(result.pagination)  // { page: 1, per_page: 20, total: 142 }
 
// Avec filtres : transactions réussies via Airtel en juin 2025
const filtered = await kadryza.transactions.list({
  status: 'SUCCESS',
  operator: 'AIRTEL',
  from: '2025-06-01T00:00:00Z',
  to: '2025-06-30T23:59:59Z',
  page: 1,
  per_page: 50
})
 
for (const tx of filtered.data) {
  console.log(`${tx.reference} — ${tx.amount} XAF — ${tx.status}`)
}

Réponse 200 OK

200 OK
{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "reference": "order_2025_001",
      "internal_ref": "KADRYZA-A1B2C3D4",
      "amount": 15000,
      "currency": "XAF",
      "operator": "AIRTEL",
      "phone_number": "+23566000000",
      "status": "SUCCESS",
      "created_at": "2025-06-15T14:30:00Z",
      "updated_at": "2025-06-15T14:31:12Z"
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "reference": "order_2025_002",
      "internal_ref": "KADRYZA-B2C3D4E5",
      "amount": 7500,
      "currency": "XAF",
      "operator": "MOOV",
      "phone_number": "+23599000000",
      "status": "SUCCESS",
      "created_at": "2025-06-16T09:15:00Z",
      "updated_at": "2025-06-16T09:16:30Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 50,
    "total": 2,
    "total_pages": 1
  }
}

Réponses d’erreur

HTTPCodeCauseSolution
400VALIDATION_ERRORParamètre de filtre invalide (ex: per_page=500)Vérifier les valeurs acceptées dans le tableau ci-dessus
401UNAUTHORIZEDClé API invalideVérifier le header Authorization

Idempotence

Le champ reference est la clé d’idempotence de Kadryza. Ce mécanisme vous protège contre les doublons en cas de retry réseau.

Comment ça fonctionne

Requête 1 : POST /v1/transactions { "reference": "order_xyz" }
 → 201 Created — Transaction créée avec statut PENDING

Requête 2 : POST /v1/transactions { "reference": "order_xyz" }
 → 409 Conflict — Transaction existante retournée (pas de doublon)

Exemple concret

Imaginons un scénario de timeout réseau :

idempotence-example.js
import Kadryza from '@kadryza/sdk'
 
const kadryza = new Kadryza({
  apiKey: process.env.KADRYZA_API_KEY
})
 
async function initierPaiementIdempotent(referenceCommande) {
  // Utiliser la référence de commande comme clé d'idempotence
  // Peu importe combien de fois cette fonction est appelée
  // avec la même référence, une seule transaction sera créée
  const transaction = await kadryza.transactions.initiate({
    reference: referenceCommande,
    amount: 25000,
    currency: 'XAF',
    operator: 'MOOV',
    phone_number: '+23599000000',
    description: 'Commande e-commerce'
  })
 
  return transaction
}
 
// Scénario : l'utilisateur clique 3 fois sur le bouton "Payer"
// ou le réseau timeout et votre système retry automatiquement
const tx1 = await initierPaiementIdempotent('cmd_2025_abc')  // → Crée la transaction
const tx2 = await initierPaiementIdempotent('cmd_2025_abc')  // → Retourne la même transaction
const tx3 = await initierPaiementIdempotent('cmd_2025_abc')  // → Retourne la même transaction
 
console.log(tx1.id === tx2.id)  // true
console.log(tx2.id === tx3.id)  // true
// Une seule transaction existe côté Kadryza
⚠️

Attention — L’idempotence est liée à la reference, pas aux autres paramètres. Si vous envoyez la même reference avec un montant différent, Kadryza retourne la transaction existante sans modifier le montant. Pour créer une transaction avec un montant différent, utilisez une reference différente.

Bonnes pratiques pour les références

ApprocheExempleCommentaire
ID de commandeorder_2025_001✅ Recommandé — lié à votre logique métier
UUID v4550e8400-e29b-41d4-a716-446655440000✅ Garanti unique
Timestamp + randompay_1718450000_abc123✅ Unique et triable
Compteur séquentiel1, 2, 3⚠️ Risque de collision si plusieurs serveurs
Chaîne vide""❌ Refusé par l’API

Exemple complet : flux de paiement

Voici un flux complet du côté serveur — de l’initiation à la réception du résultat :

complete-payment-flow.js
import Kadryza from '@kadryza/sdk'
 
const kadryza = new Kadryza({
  apiKey: process.env.KADRYZA_API_KEY
})
 
// === ÉTAPE 1 : Initier le paiement ===
async function creerPaiement(commande) {
  const transaction = await kadryza.transactions.initiate({
    reference: commande.id,
    amount: commande.total,
    currency: 'XAF',
    operator: commande.operateur,
    phone_number: commande.telephone,
    description: `Commande #${commande.id} — ${commande.articles.length} article(s)`
  })
 
  // Sauvegarder l'ID de transaction dans votre base
  await db.commandes.update(commande.id, {
    kadryza_transaction_id: transaction.id,
    kadryza_internal_ref: transaction.internal_ref,
    statut_paiement: 'EN_ATTENTE',
    paiement_expire_a: transaction.expires_at
  })
 
  return {
    transaction_id: transaction.id,
    internal_ref: transaction.internal_ref,
    expires_at: transaction.expires_at
  }
}
 
// === ÉTAPE 2 : Recevoir le webhook ===
// (Voir /api-reference/webhooks pour l'implémentation complète)
 
// === ÉTAPE 3 : Vérifier le statut (si webhook manqué) ===
async function verifierStatut(transactionId) {
  const transaction = await kadryza.transactions.get(transactionId)
 
  switch (transaction.status) {
    case 'PENDING':
      console.log('⏳ En attente de confirmation du payeur')
      break
    case 'SUCCESS':
      console.log('✅ Paiement confirmé — livrer la commande')
      break
    case 'FAILED':
      console.log('❌ Paiement refusé — proposer un autre moyen de paiement')
      break
    case 'TIMEOUT':
      console.log('⏰ Paiement expiré — proposer de réessayer')
      break
  }
 
  return transaction
}
 
// === Utilisation ===
const commande = {
  id: 'cmd_2025_789',
  total: 32000,
  operateur: 'AIRTEL',
  telephone: '+23566000000',
  articles: [
    { nom: 'Forfait Internet 10Go', prix: 12000 },
    { nom: 'Forfait Appels 500min', prix: 20000 }
  ]
}
 
const resultat = await creerPaiement(commande)
console.log('Transaction créée:', resultat.internal_ref)
console.log('Expire à:', resultat.expires_at)