UnitechPay API

Documentation technique

Introduction

Présentation de la plateforme et de ses capacités

L'API UnitechPay permet d'intégrer les paiements Wave et Orange Money dans vos applications web, mobiles ou e-commerce. Elle gère l'encaissement, les retraits automatiques, les commissions et les webhooks pour une expérience marchande complète.

URL de base

https://api.unitech.sn/api.php

Fonctionnalités

Paiements sécurisés Wave et Orange Money
3 options Orange Money : QR Code, Max It, OM standard
Soldes séparés Wave (sold_wave) et Orange (sold_om)
Retraits automatiques Wave & Orange Money en temps réel
Commission par défaut 1,5 % — personnalisable par marchand
Webhooks temps réel avec signature HMAC-SHA256
URLs de redirection personnalisables (success / cancel)
Plugin WordPress / WooCommerce officiel

Authentification

Toutes les requêtes nécessitent une clé API valide

Incluez votre clé API dans le header Authorization de chaque requête.

Authorization: Bearer VOTRE_CLE_API

Obtenir une clé API

Créez un compte marchand sur la plateforme, puis générez votre clé depuis le tableau de bord dans la section Paramètres → API.

Important : Ne partagez jamais votre clé API publiquement. Elle donne accès à vos fonds et données de transactions.

Endpoints

Liste complète des endpoints disponibles

Méthode Endpoint Description
POST/api.php?action=create_wave_paymentCréer un paiement Wave
POST/api.php?action=create_orange_qrGénérer un QR Code Orange Money
POST/api.php?action=create_orange_maxitPaiement Max It Orange
POST/api.php?action=create_orange_omPaiement Orange Money standard
POST/api.php?action=withdraw_fundsRetrait automatique MàJ
POST/api.php?action=configure_webhookConfigurer les webhooks
GET/api.php?action=balanceConsulter les soldes Wave / Orange MàJ
GET/api.php?action=transactionsLister les transactions
GET/api.php?action=withdrawalsLister les retraits
GET/api.php?action=commissionsLister les commissions

Solde marchand MàJ v1.1

Les fonds sont répartis sur deux soldes distincts

Depuis la v1.1, les fonds encaissés sont crédités sur deux soldes distincts selon le moyen de paiement utilisé par le client : sold_wave pour les paiements Wave et sold_om pour les paiements Orange Money.

sold_wave

Fonds issus des paiements Wave. Retirable uniquement via method=wave.

sold_om

Fonds issus des paiements Orange Money. Retirable via method=orange.

GET /api.php?action=balance

Réponse

{
  "success": true,
  "data": {
    "sold_wave": 45000,
    "sold_om":   12500,
    "total":     57500,
    "currency":  "XOF"
  }
}

Paiements Wave

Créer une session de paiement Wave

POST /api.php?action=create_wave_payment

Paramètres

ParamètreTypeObligatoireDescription
amountnumber✅ OuiMontant en XOF
customer_numberstring✅ OuiNuméro de téléphone du client
descriptionstringNonDescription du paiement
callback_successstringNonURL de redirection après succès
callback_cancelstringNonURL de redirection après annulation

Exemple de requête

{
  "amount": 5000,
  "customer_number": "771234567",
  "description": "Commande #123",
  "callback_success": "https://monsite.com/payment/success",
  "callback_cancel":  "https://monsite.com/payment/cancel"
}

Réponse

{
  "success": true,
  "data": {
    "transaction_id": 1,
    "reference":      "wave_66a1b2c3d4e5f_1716542100",
    "payment_url":    "https://pay.wave.com/c/cos-1xxxxx",
    "amount":         5000,
    "status":         "pending",
    "callback_urls": {
      "success": "https://monsite.com/payment/success",
      "error":   "https://monsite.com/payment/cancel"
    }
  }
}

Après paiement réussi, le montant net (après commission) est automatiquement crédité sur sold_wave du marchand. La confirmation arrive via webhook.

Paiements Orange Money

Trois modes de paiement disponibles

QR Code

Image base64 à afficher, liens deep MAXIT et OM inclus.

create_orange_qr

Max It

Redirection vers l'app Max It avec lien deep link.

create_orange_maxit

Orange Money

Paiement OM standard avec redirection.

create_orange_om

1. QR Code Orange Money

POST/api.php?action=create_orange_qr

Paramètres

ParamètreTypeObligatoireDescription
amountnumber✅ OuiMontant en XOF
referencestringNonRéférence personnalisée
descriptionstringNonDescription
callback_successstringNonURL succès
callback_cancelstringNonURL annulation

Réponse

{
  "success": true,
  "data": {
    "transaction_id": 1,
    "reference":  "commande_123",
    "qr_code":    "data:image/png;base64,iVBORw0KGgo...",
    "deep_links": {
      "MAXIT": "https://sugu.orange-sonatel.com/np/dgjuu_xxx",
      "OM":    "https://orangenonevsn.page.link/zzz"
    },
    "amount":   5000,
    "status":   "pending",
    "type":     "qr_code",
    "validity": 300,
    "callback_urls": {
      "success": "https://monsite.com/success",
      "cancel":  "https://monsite.com/cancel"
    }
  }
}

2. Paiement Max It

POST/api.php?action=create_orange_maxit

Paramètres

ParamètreTypeObligatoireDescription
amountnumber✅ OuiMontant en XOF
customer_numberstring✅ OuiNuméro du client
descriptionstringNonDescription
callback_successstringNonURL succès
callback_cancelstringNonURL annulation

Réponse

{
  "success": true,
  "data": {
    "transaction_id": 2,
    "reference":    "orange_maxit_123456",
    "payment_url":  "https://sugu.orange-sonatel.com/np/dgjuu_xxx",
    "deep_links": {
      "MAXIT": "https://sugu.orange-sonatel.com/np/dgjuu_xxx",
      "OM":    "https://orangenonevsn.page.link/zzz"
    },
    "amount": 5000,
    "status": "pending",
    "type":   "maxit"
  }
}

3. Orange Money standard

POST/api.php?action=create_orange_om

Mêmes paramètres que Max It. La payment_url retournée est le deep link OM.

{
  "success": true,
  "data": {
    "transaction_id": 3,
    "reference":    "orange_om_123456",
    "payment_url":  "https://orangenonevsn.page.link/zzz",
    "amount": 5000,
    "status": "pending",
    "type":   "orange_money"
  }
}

Après paiement Orange Money réussi, le montant net est crédité sur sold_om du marchand.

Retraits automatiques MàJ v1.1

Transfert des fonds vers Wave, Orange Money ou compte bancaire

Les retraits Wave et Orange Money sont traités automatiquement en temps réel. Chaque méthode débite le solde correspondant. En cas d'échec du payout, les fonds sont automatiquement restitués au marchand.

method=wave

Débite sold_wave. Payout automatique instantané via l'API Wave Payout.

method=orange

Débite sold_om. Cash-in automatique instantané via l'API Orange eWallet.

method=bank

Débite sold_wave + sold_om au prorata. Traitement manuel 3-5 jours.

POST /api.php?action=withdraw_funds

Paramètres

ParamètreTypeObligatoireDescription
amountnumber✅ Oui Montant à retirer en XOF. Doit être ≤ au solde disponible de la méthode choisie.
methodstring✅ Oui wave → débite sold_wave
orange → débite sold_om
bank → débite les deux au prorata
accountstring✅ Oui Numéro Wave / Orange destinataire, ou numéro de compte bancaire.

Exemple — retrait Wave

{
  "amount":  10000,
  "method":  "wave",
  "account": "771234567"
}

Réponse — succès (Wave / Orange)

{
  "success": true,
  "data": {
    "withdrawal_id":   42,
    "reference":       "WDR_7_1716542100_3829",
    "amount":          10000,
    "commission":      150,
    "commission_rate": 0.015,
    "net_amount":      9850,
    "method":          "wave",
    "status":          "processed",
    "note":            "Payout automatique effectue"
  }
}

Réponse — virement bancaire

{
  "success": true,
  "data": {
    "withdrawal_id":   43,
    "reference":       "WDR_7_1716542200_4912",
    "amount":          25000,
    "commission":      375,
    "commission_rate": 0.015,
    "net_amount":      24625,
    "method":          "bank",
    "status":          "pending",
    "note":            "Virement bancaire : traitement sous 3-5 jours ouvres"
  }
}

Réponse — payout échoué (fonds restitués)

{
  "success": false,
  "message": "Payout echoue, fonds restitues. Ref : WDR_7_1716542100_3829. Detail : Configuration Wave invalide"
}

Délais de traitement

Wave & Orange Money : payout automatique instantané

Virement bancaire : 3 à 5 jours ouvrés (traitement manuel)

Webhooks

Notifications en temps réel sur les événements de votre compte

Configurer un webhook

POST/api.php?action=configure_webhook

Paramètres

ParamètreTypeObligatoireDescription
webhook_urlstring✅ OuiURL HTTPS de votre endpoint webhook
eventsarrayNonÉvénements à écouter (tous par défaut)

Événements disponibles

payment_completed — Paiement réussi
payment_failed — Paiement échoué
payment_expired — Paiement expiré
withdrawal_processed — Retrait traité
withdrawal_failed — Retrait échoué

Exemple de payload webhook

{
  "event":          "payment_completed",
  "transaction_id": 18,
  "reference":      "wave_66a1b2_1716540000",
  "amount":         5000,
  "status":         "completed",
  "method":         "wave",
  "commission":     75,
  "net_amount":     4925,
  "timestamp":      1716540300,
  "signature":      "hmac_sha256_de_la_payload"
}

Vérification de signature (PHP)

$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_UNITECHPAY_SIGNATURE'] ?? '';
$expected  = hash_hmac('sha256', $payload, VOTRE_CLE_API);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Signature invalide');
}

$data = json_decode($payload, true);
// Traiter l'événement...

Sécurité : Vérifiez toujours la signature HMAC-SHA256 avant de traiter un webhook. Votre clé API est utilisée comme secret de signature.

Plugins & Intégrations

Solutions prêtes à l'emploi pour vos projets

Plugin WordPress Officiel

Intégrez Wave et Orange Money dans votre site WordPress ou boutique WooCommerce en quelques minutes.

Compatible WooCommerce
Webhooks intégrés
Installation en 1 clic
Interface responsive

Guide d'installation WordPress

1

Installation

Depuis votre admin WordPress : Extensions → Ajouter → Rechercher "UnitechPay" → Installer & Activer.

2

Configuration

Allez dans UnitechPay Settings et renseignez vos numéros Wave et Orange Money.

3

WooCommerce

Activez UnitechPay comme méthode de paiement dans WooCommerce → Réglages → Paiements.

Codes d'erreur

Réponses HTTP retournées par l'API

Code HTTPMessageDescription
200SuccessRequête traitée avec succès
400Bad RequestParamètres manquants, invalides ou solde insuffisant
401UnauthorizedClé API manquante ou invalide
404Not FoundAction inconnue ou ressource introuvable
500Internal Server ErrorErreur serveur ou échec payout (fonds restitués)

Format des erreurs

{
  "success": false,
  "message": "Description de l'erreur",
  "code":    400
}

Exemples d'intégration

Code prêt à l'emploi dans différents langages

PHP — Paiement Wave + Consultation des soldes

<?php
$api_url = 'https://api.unitech.sn/api.php';
$api_key = 'VOTRE_CLE_API';

function unitechRequest($action, $data = [], $method = 'POST') {
    global $api_url, $api_key;
    $url = $api_url . '?action=' . $action;
    $ch  = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer ' . $api_key,
            'Content-Type: application/json'
        ],
    ]);
    if ($method === 'POST') {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    }
    $response = curl_exec($ch);
    curl_close($ch);
    return json_decode($response, true);
}

// Consulter les soldes (sold_wave + sold_om)
$balance = unitechRequest('balance', [], 'GET');
echo "Wave : "  . $balance['data']['sold_wave'] . " XOF\n";
echo "Orange : " . $balance['data']['sold_om']   . " XOF\n";
echo "Total : "  . $balance['data']['total']      . " XOF\n";

// Créer un paiement Wave
$result = unitechRequest('create_wave_payment', [
    'amount'           => 5000,
    'customer_number'  => '771234567',
    'description'      => 'Commande #123',
    'callback_success' => 'https://monsite.com/success',
    'callback_cancel'  => 'https://monsite.com/cancel',
]);

if ($result['success']) {
    header('Location: ' . $result['data']['payment_url']);
    exit;
}

// Retrait Wave automatique
$withdrawal = unitechRequest('withdraw_funds', [
    'amount'  => 10000,
    'method'  => 'wave',
    'account' => '771234567',
]);

if ($withdrawal['success']) {
    echo "Retrait traité : " . $withdrawal['data']['net_amount'] . " XOF net\n";
    echo "Statut : "         . $withdrawal['data']['status'] . "\n";
}
?>

PHP — QR Code Orange Money

<?php
$result = unitechRequest('create_orange_qr', [
    'amount'           => 2500,
    'reference'        => 'cmd_' . uniqid(),
    'description'      => 'Paiement QR Code',
    'callback_success' => 'https://monsite.com/success',
    'callback_cancel'  => 'https://monsite.com/cancel',
]);

if ($result['success']) {
    $qr   = $result['data']['qr_code'];   // data:image/png;base64,...
    $ref  = $result['data']['reference'];
    echo '<img src="' . $qr . '" alt="QR Code" />';
    echo '<p>Référence : ' . $ref . '</p>';
}
?>

Node.js — Classe UnitechPay complète

const axios = require('axios');

class UnitechPay {
    constructor(apiKey) {
        this.client = axios.create({
            baseURL: 'https://api.unitech.sn/api.php',
            headers: {
                'Authorization': `Bearer ${apiKey}`,
                'Content-Type': 'application/json',
            },
            timeout: 30000,
        });
    }

    async _post(action, data) {
        const res = await this.client.post(`?action=${action}`, data);
        return res.data;
    }

    async _get(action, params = {}) {
        const res = await this.client.get(`?action=${action}`, { params });
        return res.data;
    }

    // Soldes Wave + Orange
    async getBalance() {
        return this._get('balance');
    }

    // Paiement Wave
    async wavePayment(amount, phone, description, callbacks = {}) {
        return this._post('create_wave_payment', {
            amount, customer_number: phone, description,
            callback_success: callbacks.success,
            callback_cancel:  callbacks.cancel,
        });
    }

    // QR Code Orange Money
    async orangeQR(amount, reference, description, callbacks = {}) {
        return this._post('create_orange_qr', {
            amount, reference, description,
            callback_success: callbacks.success,
            callback_cancel:  callbacks.cancel,
        });
    }

    // Retrait automatique
    async withdraw(amount, method, account) {
        return this._post('withdraw_funds', { amount, method, account });
    }
}

// Utilisation
(async () => {
    const pay = new UnitechPay('VOTRE_CLE_API');

    // Soldes
    const bal = await pay.getBalance();
    console.log(`Wave: ${bal.data.sold_wave} XOF — Orange: ${bal.data.sold_om} XOF`);

    // Paiement Wave
    const wave = await pay.wavePayment(5000, '771234567', 'Commande #123', {
        success: 'https://monapp.com/success',
        cancel:  'https://monapp.com/cancel',
    });
    console.log('URL de paiement:', wave.data.payment_url);

    // Retrait Wave
    const wd = await pay.withdraw(10000, 'wave', '771234567');
    console.log(`Retrait: ${wd.data.net_amount} XOF — ${wd.data.status}`);
})();

Python — Classe UnitechPay

import requests

class UnitechPay:
    BASE_URL = "https://api.unitech.sn/api.php"

    def __init__(self, api_key: str):
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        })

    def _post(self, action: str, data: dict) -> dict:
        r = self.session.post(f"{self.BASE_URL}?action={action}", json=data, timeout=30)
        r.raise_for_status()
        return r.json()

    def _get(self, action: str, params: dict = {}) -> dict:
        r = self.session.get(f"{self.BASE_URL}?action={action}", params=params, timeout=30)
        r.raise_for_status()
        return r.json()

    def get_balance(self) -> dict:
        return self._get("balance")

    def wave_payment(self, amount, phone, description="", success_url="", cancel_url=""):
        return self._post("create_wave_payment", {
            "amount": amount, "customer_number": phone,
            "description": description,
            "callback_success": success_url, "callback_cancel": cancel_url,
        })

    def orange_qr(self, amount, reference="", description="", success_url="", cancel_url=""):
        return self._post("create_orange_qr", {
            "amount": amount, "reference": reference,
            "description": description,
            "callback_success": success_url, "callback_cancel": cancel_url,
        })

    def withdraw(self, amount: float, method: str, account: str) -> dict:
        return self._post("withdraw_funds", {
            "amount": amount, "method": method, "account": account,
        })


# Utilisation
if __name__ == "__main__":
    api = UnitechPay("VOTRE_CLE_API")

    # Soldes
    bal = api.get_balance()
    print(f"Wave: {bal['data']['sold_wave']} XOF")
    print(f"Orange: {bal['data']['sold_om']} XOF")
    print(f"Total: {bal['data']['total']} XOF")

    # Paiement Wave
    w = api.wave_payment(5000, "771234567", "Test",
                         "https://monsite.com/success",
                         "https://monsite.com/cancel")
    print("URL:", w["data"]["payment_url"])

    # Retrait Orange Money
    r = api.withdraw(8000, "orange", "771234567")
    print(f"Retrait: {r['data']['net_amount']} XOF — {r['data']['status']}")

Flutter/Dart — Intégration complète

import 'package:http/http.dart' as http;
import 'dart:convert';

class UnitechPay {
  static const String _base = 'https://api.unitech.sn/api.php';
  final String _apiKey;

  UnitechPay(this._apiKey);

  Future<Map<String, dynamic>> _post(String action, Map<String, dynamic> body) async {
    final res = await http.post(
      Uri.parse('$_base?action=$action'),
      headers: {
        'Authorization': 'Bearer $_apiKey',
        'Content-Type': 'application/json',
      },
      body: json.encode(body),
    ).timeout(const Duration(seconds: 30));
    return json.decode(res.body);
  }

  Future<Map<String, dynamic>> _get(String action) async {
    final res = await http.get(
      Uri.parse('$_base?action=$action'),
      headers: {'Authorization': 'Bearer $_apiKey'},
    ).timeout(const Duration(seconds: 30));
    return json.decode(res.body);
  }

  Future<Map<String, dynamic>> getBalance() => _get('balance');

  Future<Map<String, dynamic>> wavePayment({
    required double amount,
    required String phone,
    String description = '',
    String successUrl  = '',
    String cancelUrl   = '',
  }) => _post('create_wave_payment', {
    'amount':           amount,
    'customer_number':  phone,
    'description':      description,
    'callback_success': successUrl,
    'callback_cancel':  cancelUrl,
  });

  Future<Map<String, dynamic>> orangeQR({
    required double amount,
    String reference   = '',
    String description = '',
    String successUrl  = '',
    String cancelUrl   = '',
  }) => _post('create_orange_qr', {
    'amount':           amount,
    'reference':        reference,
    'description':      description,
    'callback_success': successUrl,
    'callback_cancel':  cancelUrl,
  });

  Future<Map<String, dynamic>> withdraw({
    required double amount,
    required String method,   // 'wave' | 'orange' | 'bank'
    required String account,
  }) => _post('withdraw_funds', {
    'amount':  amount,
    'method':  method,
    'account': account,
  });
}

// Utilisation dans un widget
void _example() async {
  final api = UnitechPay('VOTRE_CLE_API');

  // Soldes
  final bal = await api.getBalance();
  print('Wave: ${bal['data']['sold_wave']} XOF');
  print('Orange: ${bal['data']['sold_om']} XOF');

  // Paiement Wave
  final wave = await api.wavePayment(
    amount:      5000,
    phone:       '771234567',
    description: 'Commande Flutter',
    successUrl:  'https://monapp.com/success',
    cancelUrl:   'https://monapp.com/cancel',
  );
  print('URL: ${wave['data']['payment_url']}');

  // Retrait automatique
  final wd = await api.withdraw(
    amount:  10000,
    method:  'wave',
    account: '771234567',
  );
  print('Net: ${wd['data']['net_amount']} XOF — ${wd['data']['status']}');
}