v1.0
Se connecter

API Marchand GeniusPay

Intégrez les paiements mobiles et par carte dans vos applications en quelques minutes.

Base URL
https://pay.genius.ci/api/v1/merchant
🧪

Sandbox

Testez votre intégration sans frais. Les transactions sont simulées.

Production

Transactions réelles. Activez le mode live dans vos paramètres.

Authentification

Toutes les requêtes doivent inclure vos clés API dans les headers HTTP.

Header Description
X-API-Key Votre clé publique (pk_sandbox_... ou pk_live_...)
X-API-Secret Votre clé secrète (sk_sandbox_... ou sk_live_...)
Content-Type application/json

Exemple avec cURL

curl -X POST https://pay.genius.ci/api/v1/merchant/payments \
  -H "X-API-Key: pk_sandbox_xxxxxxxx" \
  -H "X-API-Secret: sk_sandbox_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"amount": 5000, "customer": {"phone": "+221771234567"}}'

Démarrage rapide - 2 lignes de code

La façon la plus simple d'intégrer GeniusPay. Créez un paiement et redirigez votre client vers notre page de checkout sécurisée où il choisira son moyen de paiement.

✨ Intégration minimale

// 1. Créer le paiement (sans spécifier payment_method)
$response = Http::withHeaders([
    'X-API-Key' => 'pk_live_xxx',
    'X-API-Secret' => 'sk_live_xxx',
])->post('https://pay.genius.ci/api/v1/merchant/payments', [
    'amount' => 15000,
    'description' => 'Commande #123',
]);

// 2. Rediriger vers la page de checkout GeniusPay
return redirect($response['data']['checkout_url']);

Rapide

Intégration en 2 lignes, aucune logique de paiement à gérer

Sécurisé

Page de checkout hébergée et sécurisée par GeniusPay

Tous les moyens

Wave, Orange, MTN, Moov, Cartes bancaires

Comment ça marche ?

En omettant le paramètre payment_method, GeniusPay génère une URL vers notre page de checkout personnalisée. Votre client y choisira son moyen de paiement préféré. Une fois le paiement effectué, il sera redirigé et vous recevrez un webhook.

POST

Initier un paiement

Crée une nouvelle transaction et retourne une URL de paiement.

/payments

Paramètres

Paramètre Type Requis Description
amount number Montant en XOF (min: 200)
currency string - Devise (défaut: XOF)
payment_method string - wave, paystack, pawapay, orange_money, mtn_money, mobile_money, card
gateway string - Gateway explicite: wave, pawapay, orange_money, mtn_momo, moov_money
mmo_provider NEW string - Code fournisseur MMO PawaPay (ex: ORANGE_CIV). Voir Providers
description string - Description du paiement (max 500 car.)
customer.name string - Nom du client
customer.email string - Email du client
customer.phone string - Téléphone du client (format international recommandé)
customer.country NEW string - Code pays ISO2 (ex: CI, SN, GH). Utilisé pour le routage PawaPay
success_url string - URL de redirection après succès
error_url string - URL de redirection après échec
metadata object - Données personnalisées

Requête

{
  "amount": 15000,
  "payment_method": "wave",
  "description": "Commande #12345",
  "customer": {
    "name": "Amadou Diallo",
    "email": "amadou@example.com",
    "phone": "+221771234567"
  },
  "metadata": {
    "order_id": "12345"
  }
}

Réponse 201

{
  "success": true,
  "data": {
    "id": 456,
    "reference": "MTX-A1B2C3D4E5",
    "amount": 15000,
    "fees": 450,
    "net_amount": 14550,
    "status": "pending",
    "payment_url": "https://wave.com/...",
    "gateway": "wave",
    "environment": "sandbox"
  }
}
PAGE

Page de Checkout GeniusPay

Quand vous initiez un paiement sans spécifier de payment_method, l'API retourne une checkout_url vers notre page de paiement hébergée.

Aperçu de la page de checkout
🏪

Paiement sécurisé

Votre Boutique

15 000 FCFA
Wave
Wave
Orange Money
Orange Money
MTN MoMo
MTN MoMo
Mastercard
Carte bancaire

Réponse API (mode checkout)

{
  "success": true,
  "data": {
    "id": 123,
    "reference": "MTX-A1B2C3D4E5",
    "amount": 15000,
    "currency": "XOF",
    "status": "pending",
    "checkout_url": "https://pay.genius.ci/checkout/MTX-A1B2C3D4E5",
    "payment_url": "https://pay.genius.ci/checkout/MTX-A1B2C3D4E5",
    "environment": "sandbox",
    "expires_at": "2024-12-16T14:00:00.000000Z"
  }
}

✅ Avantages

  • • Aucune gestion des moyens de paiement côté client
  • • Interface optimisée pour la conversion
  • • Mise à jour automatique des providers
  • • Design responsive (mobile/desktop)

📌 Bon à savoir

  • • Le lien expire après 24 heures
  • • Webhooks envoyés après paiement
  • • Redirection vers success_url/error_url
  • • Compatible sandbox et production
GET

Lister les paiements

/payments

Paramètres de query

Paramètre Description
status Filtrer par statut (pending, completed, failed)
from Date de début (YYYY-MM-DD)
to Date de fin (YYYY-MM-DD)
per_page Résultats par page (défaut: 20, max: 100)
GET

Récupérer un paiement

/payments/{reference}
NOUVEAU

PawaPay — Mobile Money Afrique

PawaPay est un agrégateur de mobile money. GeniusPay intègre actuellement 12 pays africains avec 24 opérateurs MMO disponibles. Le système détecte automatiquement le pays depuis le numéro de téléphone et affiche uniquement les opérateurs disponibles.

🔄

Auto-routing

Envoyez le numéro, GeniusPay détecte pays et opérateur automatiquement

💱

Multi-devises

9 devises supportées avec conversion automatique vers XOF

🎯

Choix explicite

Spécifiez mmo_provider pour cibler un opérateur

🌍

12 Pays

Bénin, Cameroun, CI, Congo, RD Congo, Gabon, Kenya, Rwanda, Sénégal, Sierra Leone, Ouganda, Zambie

Exemples d'utilisation

Le numéro de téléphone suffit. GeniusPay détecte automatiquement le pays et l'opérateur. La devise locale est également détectée et convertie en XOF.

// Exemple: Client au Kenya
{
  "amount": 1000,
  "currency": "KES",
  "payment_method": "pawapay",
  "customer": {
    "phone": "+254712345678"
  }
}
// Détection auto: Kenya → M-Pesa Safaricom
// Conversion: 1000 KES × 4.5 = 4500 XOF stockés

Spécifiez directement le code opérateur pour forcer le routage vers un opérateur précis.

// Exemple: Forcer Orange Money Sénégal
{
  "amount": 5000,
  "currency": "XOF",
  "payment_method": "pawapay",
  "mmo_provider": "ORANGE_SEN",
  "customer": {
    "phone": "+221771234567",
    "country": "SN"
  }
}

Pour la RD Congo qui supporte 2 devises (CDF et USD), spécifiez la devise souhaitée.

// Exemple: RD Congo en USD
{
  "amount": 10,
  "currency": "USD",
  "payment_method": "pawapay",
  "customer": {
    "phone": "+243XX XXX XXXX",
    "country": "CD"
  }
}
// Conversion: 10 USD × 600 = 6000 XOF

Guide d'intégration PawaPay - 3 étapes

1

Mode Simple (Recommandé)

Envoyez juste le numéro de téléphone avec le préfixe international. GeniusPay détecte le pays, l'opérateur et la devise automatiquement.

curl -X POST https://api.geniuspay.com/api/v1/merchant/payments \
  -H "X-API-Key: pk_live_xxx" \
  -H "X-API-Secret: sk_live_xxx" \
  -d '{
    "amount": 5000,
    "payment_method": "pawapay",
    "customer": {
      "phone": "+221771234567"
    }
  }'
# ✅ Auto-détection: Sénégal → Free/Orange Money → XOF
2

Mode Multi-Devises

Pour les pays avec plusieurs devises (RD Congo: CDF/USD), spécifiez la devise souhaitée. La conversion vers XOF est automatique.

{
  "amount": 1000,
  "currency": "KES",
  "payment_method": "pawapay",
  "customer": {
    "phone": "+254712345678"
  }
}
// Kenya: 1000 KES → 4500 XOF stockés (taux: 4.5)
3

Mode Avancé (Opérateur Spécifique)

Forcez un opérateur précis avec le code mmo_provider. Consultez le tableau ci-dessous pour les codes.

{
  "amount": 5000,
  "currency": "XOF",
  "payment_method": "pawapay",
  "mmo_provider": "MTN_MOMO_BEN",
  "customer": {
    "phone": "+229XXXXXXXX",
    "country": "BJ"
  }
}
// Force MTN Bénin même si le numéro est Moov

💡 Bonnes pratiques

  • Toujours utiliser le préfixe international (+221, +254, etc.)
  • • Laissez GeniusPay détecter l'opérateur automatiquement (meilleur taux de succès)
  • • Pour les devises étrangères, spécifiez currency même si auto-détectée
  • • Consultez GET /pawapay/providers pour lister dynamiquement les opérateurs
  • • Les conversions sont transparentes: envoyez en devise locale, recevez en XOF
GET

Fournisseurs MMO disponibles

Endpoint de découverte pour lister les fournisseurs MMO par pays ou tous les pays supportés.

/pawapay/providers?country=CI

Paramètre

Paramètre Type Description
country string Code pays ISO2 (ex: CI, SN, GH). Si omis, retourne tous les pays

Réponse (un pays)

{
  "success": true,
  "data": {
    "country": "CI",
    "country_iso3": "CIV",
    "country_name": "Côte d'Ivoire",
    "currency": "XOF",
    "providers": [
      { "code": "ORANGE_CIV", "name": "Orange Money", "type": "MMO" },
      { "code": "MTN_MOMO_CIV", "name": "MTN Mobile Money", "type": "MMO" },
      { "code": "MOOV_CIV", "name": "Moov Money", "type": "MMO" },
      { "code": "WAVE_CIV", "name": "Wave", "type": "MMO" }
    ]
  }
}

Réponse (tous les pays)

{
  "success": true,
  "data": {
    "countries": [
      {
        "country": "CI",
        "country_iso3": "CIV",
        "country_name": "Côte d'Ivoire",
        "currency": "XOF",
        "providers": [ ... ]
      },
      // ... 11 autres pays
    ],
    "total_countries": 12
  }
}

🌍 Pays et opérateurs disponibles

Important: Seuls les pays listés ci-dessous sont actuellement disponibles . Le système détecte automatiquement le pays depuis le numéro de téléphone et affiche uniquement les opérateurs disponibles.

Pays ISO2 Devise Opérateurs Codes Provider
🇧🇯 Bénin BJ XOF MTN, Moov MTN_MOMO_BEN
MOOV_BEN
🇨🇲 Cameroun CM XAF MTN, Orange MTN_MOMO_CMR
ORANGE_CMR
🇨🇮 Côte d'Ivoire CI XOF Wave (Direct), MTN, Orange Via Wave & Paystack
🇨🇩 RD Congo CD CDF/USD Airtel, Orange, Vodacom AIRTEL_COD
ORANGE_COD
VODACOM_MPESA_COD
🇬🇦 Gabon GA XAF Airtel AIRTEL_GAB
🇰🇪 Kenya KE KES M-Pesa (Safaricom) MPESA_KEN
🇨🇬 République du Congo CG XAF Airtel, MTN AIRTEL_COG
MTN_MOMO_COG
🇷🇼 Rwanda RW RWF Airtel, MTN AIRTEL_RWA
MTN_MOMO_RWA
🇸🇳 Sénégal SN XOF Free, Orange FREE_SEN
ORANGE_SEN
🇸🇱 Sierra Leone SL SLE Orange ORANGE_SLE
🇺🇬 Ouganda UG UGX Airtel, MTN AIRTEL_UGA
MTN_MOMO_UGA
🇿🇲 Zambie ZM ZMW MTN, Zamtel MTN_MOMO_ZMB
ZAMTEL_ZMB
💱

Devises Supportées

9 devises avec conversion automatique vers XOF:

XOF XAF CDF USD KES RWF SLE UGX ZMW
💡

Astuce d'intégration

Utilisez GET /pawapay/providers?country=CI pour obtenir dynamiquement les codes opérateurs.

Les conversions de devises sont transparentes: envoyez dans la devise locale, GeniusPay stocke en XOF.

GET

Informations du compte

/account
GET

Solde du compte

/account/balance
{
  "success": true,
  "data": {
    "available": 1250000,
    "pending": 75000,
    "total": 1325000,
    "currency": "XOF"
  }
}

Webhooks

Recevez des notifications en temps réel sur les événements de vos paiements. L'intégration webhook est identique pour Sandbox et Live, seules les clés changent.

🔑 Sandbox vs Live

Aspect Sandbox Live
Secret Webhook whsec_sandbox_xxx whsec_live_xxx
Header Environment X-Webhook-Environment: sandbox X-Webhook-Environment: live
Payload Field "environment": "sandbox" "environment": "live"
Code d'intégration ✅ Identique ✅ Identique
GET /webhooks Lister les webhooks
POST /webhooks Créer un webhook
PUT /webhooks/{id} Modifier un webhook
DELETE /webhooks/{id} Supprimer un webhook
POST /webhooks/{id}/test Tester un webhook

Événements webhook

Événement Description
payment.initiated Paiement initié
payment.success Paiement réussi
payment.failed Paiement échoué
payment.cancelled Paiement annulé
payment.refunded Paiement remboursé
payment.expired Paiement expiré
cashout.requested Demande de retrait
cashout.approved Retrait approuvé
cashout.completed Retrait complété
cashout.failed Retrait échoué
webhook.test Test de webhook

Configuration Webhook

✅ Créer un webhook

curl -X POST https://api.geniuspay.ci/merchant/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Mon webhook",
    "url": "https://example.com/webhooks/geniuspay",
    "events": ["payment.success", "payment.failed", "cashout.completed"]
  }'

Le secret webhook sera retourné uniquement à la création. Conservez-le précieusement!

Payload webhook

Le payload est identique pour Sandbox et Live. Seul le champ "environment" change.

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "event": "payment.success",
  "timestamp": 1735587600,
  "created_at": "2025-12-30T12:00:00.000000Z",
  "data": {
    "object": "transaction",
    "id": 12345,
    "reference": "TXN-2025-001",
    "amount": 10000.00,
    "currency": "XOF",
    "fees": 250.00,
    "net_amount": 9750.00,
    "status": "completed",
    "payment_method": "mobile_money",
    "provider": "wave",
    "customer_name": "Jean Kouassi",
    "customer_phone": "+2250748123456",
    "merchant_id": 25,
    "metadata": {
      "order_id": "ORD-2025-123",
      "customer_email": "jean@example.com"
    }
  },
  "environment": "live",
  "api_version": "2024-01-01"
}

Sécurité des webhooks

Vérifiez toujours la signature des webhooks pour vous assurer qu'ils proviennent bien de GeniusPay.

Important

Ne traitez jamais un webhook sans vérifier sa signature.

Headers webhook

Header Description
Content-Type application/json
X-Webhook-Signature Signature HMAC-SHA256
X-Webhook-Timestamp Timestamp Unix de l'envoi
X-Webhook-Event Type d'événement
X-Webhook-Delivery ID unique de livraison (optionnel)
X-Webhook-Environment sandbox ou live
User-Agent GeniusPay-Webhook/1.0

Vérification de la signature

Format: signature = HMAC-SHA256(timestamp + "." + json_payload, secret)

// Récupérer les headers
$signature = $request->header('X-Webhook-Signature');
$timestamp = $request->header('X-Webhook-Timestamp');
$event = $request->header('X-Webhook-Event');

// Récupérer le payload JSON
$payload = $request->all();

// Construire la donnée à vérifier
$data = $timestamp . '.' . json_encode($payload);

// Calculer la signature attendue
$secret = 'whsec_xxxxxxxx'; // Votre clé secrète webhook
$expectedSignature = hash_hmac('sha256', $data, $secret);

// Vérifier la signature
if (!hash_equals($expectedSignature, $signature)) {
    return response()->json([
        'status' => 401,
        'detail' => 'Invalid signature'
    ], 401);
}

// Vérifier le timestamp (protection replay attack)
if (abs(time() - (int)$timestamp) > 300) { // 5 minutes
    return response()->json([
        'status' => 400,
        'detail' => 'Timestamp too old'
    ], 400);
}

// Traiter l'événement selon son type
switch ($event) {
    case 'payment.success':
        // Marquer la commande comme payée
        break;
    case 'payment.failed':
        // Notifier le client
        break;
}

📘 Documentation complète: Consultez le Guide d'Intégration Webhook pour des exemples en PHP, Node.js, Python et Java.

Statuts des paiements

pending

En attente de paiement

processing

En cours de traitement

completed

Paiement réussi

failed

Paiement échoué

cancelled

Paiement annulé

refunded

Paiement remboursé

Méthodes de paiement

Code Nom Pays
wave Wave SN, CI, ML, BF
orange_money Orange Money SN, CI, ML, BF
mtn_money MTN Mobile Money CI, BF
pawapay NEW PawaPay (Mobile Money Afrique) 20 pays (BJ, BF, CM, CI, CD, ET, GA, GH, KE, SN, ...)
card Carte bancaire (Visa, Mastercard) International

Conseil

Omettez le paramètre payment_method pour laisser le client choisir sur la page de checkout GeniusPay. C'est l'approche recommandée pour maximiser les conversions.

Codes d'erreur

Code HTTP Description
MISSING_API_KEY 401 Clé API manquante
INVALID_API_KEY 401 Clé API invalide
MERCHANT_INACTIVE 403 Compte désactivé
PAYMENT_INIT_FAILED 400 Échec d'initialisation
TRANSACTION_NOT_FOUND 404 Transaction introuvable
VALIDATION_ERROR 422 Données invalides
COUNTRY_NOT_SUPPORTED 404 Pays non supporté par PawaPay

Exemples d'intégration

RECOMMANDÉ

Mode Checkout (2 lignes)

Sans payment_method, le client choisit son moyen de paiement sur la page GeniusPay.

// Intégration en 2 lignes avec le SDK Laravel
$payment = GeniusPay::checkout(15000, 'Commande #123');
return redirect($payment->checkoutUrl);

// Ou avec Http natif
$response = Http::withHeaders([
    'X-API-Key' => 'pk_live_xxx',
    'X-API-Secret' => 'sk_live_xxx',
])->post('https://pay.genius.ci/api/v1/merchant/payments', [
    'amount' => 15000,
    'description' => 'Commande #123',
    // PAS de payment_method = Page checkout GeniusPay
]);

return redirect($response['data']['checkout_url']);
// Intégration simplifiée
const response = await fetch('https://pay.genius.ci/api/v1/merchant/payments', {
  method: 'POST',
  headers: {
    'X-API-Key': 'pk_live_xxx',
    'X-API-Secret': 'sk_live_xxx',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 15000,
    description: 'Commande #123',
    // PAS de payment_method = Page checkout GeniusPay
  }),
});

const { data } = await response.json();
window.location.href = data.checkout_url;
# Intégration simplifiée
import requests

response = requests.post(
    'https://pay.genius.ci/api/v1/merchant/payments',
    headers={
        'X-API-Key': 'pk_live_xxx',
        'X-API-Secret': 'sk_live_xxx',
    },
    json={
        'amount': 15000,
        'description': 'Commande #123',
        # PAS de payment_method = Page checkout GeniusPay
    }
)

checkout_url = response.json()['data']['checkout_url']
# Rediriger le client vers checkout_url
// Intégration en 2 lignes avec le SDK Flutter
final payment = await geniusPay.checkout(
  amount: 15000, 
  description: 'Commande #123',
);
launchUrl(Uri.parse(payment.checkoutUrl!));
ALTERNATIF

Mode Direct (méthode spécifiée)

Avec payment_method spécifié, redirection directe vers le gateway.

$response = Http::withHeaders([
    'X-API-Key' => 'pk_live_xxx',
    'X-API-Secret' => 'sk_live_xxx',
])->post('https://pay.genius.ci/api/v1/merchant/payments', [
    'amount' => 15000,
    'payment_method' => 'wave', // Redirection directe vers Wave
    'customer' => [
        'phone' => '+221771234567',
    ],
]);

return redirect($response['data']['payment_url']);
const response = await fetch('https://pay.genius.ci/api/v1/merchant/payments', {
  method: 'POST',
  headers: {
    'X-API-Key': 'pk_live_xxx',
    'X-API-Secret': 'sk_live_xxx',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 15000,
    payment_method: 'wave', // Redirection directe vers Wave
    customer: { phone: '+221771234567' },
  }),
});

const { data } = await response.json();
window.location.href = data.payment_url;