📚 Documentation API Movapay
Intégrez facilement les paiements dans votre application avec notre API simple et puissante
🚀 Démarrage Rapide
- Créez votre compte développeur sur Movapay
- Récupérez vos identifiants (Client ID et Client Secret)
- Configurez votre URL de callback pour les notifications
- Intégrez nos endpoints dans votre application
🔐 Authentification
L'API Movapay utilise OAuth2 Client Credentials Flow. Vous devez inclure votre token d'accès dans l'en-tête Authorization :
Authorization: Bearer YOUR_ACCESS_TOKEN
🔔 Configuration des Webhooks
Configurez votre URL de callback dans votre tableau de bord développeur pour recevoir les notifications de paiement en temps réel.
URL de callback: https://votre-site.com/webhook/payment
Méthode: POST
Content-Type: application/json
💳 Initier un Paiement
POST /api/payments/initiate/
Crée une nouvelle transaction de paiement et génère une URL de paiement sécurisée.
import requests
import json
# Configuration
API_BASE_URL = "https://api.movapay.com"
CLIENT_ID = "your_client_id"
CLIENT_SECRET = "your_client_secret"
# Obtenir le token d'accès
def get_access_token():
token_url = f"{API_BASE_URL}/oauth/token/"
data = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
response = requests.post(token_url, data=data)
return response.json()["access_token"]
# Initier un paiement
def initiate_payment(amount, currency="XOF", description="", customer_email="", customer_phone=""):
token = get_access_token()
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
payload = {
"amount": amount,
"currency": currency,
"description": description,
"customer_email": customer_email,
"customer_phone": customer_phone,
"return_url": "https://votre-site.com/payment/success",
"cancel_url": "https://votre-site.com/payment/cancel"
}
response = requests.post(
f"{API_BASE_URL}/api/payments/initiate/",
headers=headers,
json=payload
)
return response.json()
# Exemple d'utilisation
if __name__ == "__main__":
result = initiate_payment(
amount=5000,
description="Paiement pour commande #12345",
customer_email="client@example.com",
customer_phone="+2250701234567"
)
print(json.dumps(result, indent=2))
const axios = require('axios');
// Configuration
const API_BASE_URL = 'https://api.movapay.com';
const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
// Obtenir le token d'accès
async function getAccessToken() {
try {
const response = await axios.post(`${API_BASE_URL}/oauth/token/`, {
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
});
return response.data.access_token;
} catch (error) {
console.error('Erreur lors de l\'obtention du token:', error);
throw error;
}
}
// Initier un paiement
async function initiatePayment(amount, currency = 'XOF', description = '', customerEmail = '', customerPhone = '') {
try {
const token = await getAccessToken();
const payload = {
amount: amount,
currency: currency,
description: description,
customer_email: customerEmail,
customer_phone: customerPhone,
return_url: 'https://votre-site.com/payment/success',
cancel_url: 'https://votre-site.com/payment/cancel'
};
const response = await axios.post(`${API_BASE_URL}/api/payments/initiate/`, payload, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
return response.data;
} catch (error) {
console.error('Erreur lors de l\'initiation du paiement:', error);
throw error;
}
}
// Exemple d'utilisation
initiatePayment(5000, 'XOF', 'Paiement pour commande #12345', 'client@example.com', '+2250701234567')
.then(result => console.log(result))
.catch(error => console.error(error));
// Configuration
const API_BASE_URL = 'https://api.movapay.com';
const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
// Obtenir le token d'accès
async function getAccessToken() {
try {
const response = await fetch(`${API_BASE_URL}/oauth/token/`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
})
});
const data = await response.json();
return data.access_token;
} catch (error) {
console.error('Erreur lors de l\'obtention du token:', error);
throw error;
}
}
// Initier un paiement
async function initiatePayment(amount, currency = 'XOF', description = '', customerEmail = '', customerPhone = '') {
try {
const token = await getAccessToken();
const payload = {
amount: amount,
currency: currency,
description: description,
customer_email: customerEmail,
customer_phone: customerPhone,
return_url: 'https://votre-site.com/payment/success',
cancel_url: 'https://votre-site.com/payment/cancel'
};
const response = await fetch(`${API_BASE_URL}/api/payments/initiate/`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
return await response.json();
} catch (error) {
console.error('Erreur lors de l\'initiation du paiement:', error);
throw error;
}
}
// Exemple d'utilisation
initiatePayment(5000, 'XOF', 'Paiement pour commande #12345', 'client@example.com', '+2250701234567')
.then(result => console.log(result))
.catch(error => console.error(error));
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
public class MovapayAPI {
private static final String API_BASE_URL = "https://api.movapay.com";
private static final String CLIENT_ID = "your_client_id";
private static final String CLIENT_SECRET = "your_client_secret";
private static final HttpClient client = HttpClient.newHttpClient();
private static final ObjectMapper mapper = new ObjectMapper();
// Obtenir le token d'accès
public static String getAccessToken() throws Exception {
String tokenUrl = API_BASE_URL + "/oauth/token/";
String formData = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s",
CLIENT_ID, CLIENT_SECRET);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(tokenUrl))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
Map result = mapper.readValue(response.body(), Map.class);
return (String) result.get("access_token");
}
// Initier un paiement
public static Map initiatePayment(double amount, String currency, String description,
String customerEmail, String customerPhone) throws Exception {
String token = getAccessToken();
Map payload = Map.of(
"amount", amount,
"currency", currency,
"description", description,
"customer_email", customerEmail,
"customer_phone", customerPhone,
"return_url", "https://votre-site.com/payment/success",
"cancel_url", "https://votre-site.com/payment/cancel"
);
String jsonPayload = mapper.writeValueAsString(payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(API_BASE_URL + "/api/payments/initiate/"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
return mapper.readValue(response.body(), Map.class);
}
public static void main(String[] args) {
try {
Map result = initiatePayment(5000.0, "XOF",
"Paiement pour commande #12345", "client@example.com", "+2250701234567");
System.out.println(mapper.writeValueAsString(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
<?php
class MovapayAPI {
private $apiBaseUrl = 'https://api.movapay.com';
private $clientId = 'your_client_id';
private $clientSecret = 'your_client_secret';
// Obtenir le token d'accès
public function getAccessToken() {
$tokenUrl = $this->apiBaseUrl . '/oauth/token/';
$postData = http_build_query([
'grant_type' => 'client_credentials',
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret
]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $tokenUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded'
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
return $data['access_token'];
}
// Initier un paiement
public function initiatePayment($amount, $currency = 'XOF', $description = '',
$customerEmail = '', $customerPhone = '') {
$token = $this->getAccessToken();
$payload = [
'amount' => $amount,
'currency' => $currency,
'description' => $description,
'customer_email' => $customerEmail,
'customer_phone' => $customerPhone,
'return_url' => 'https://votre-site.com/payment/success',
'cancel_url' => 'https://votre-site.com/payment/cancel'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->apiBaseUrl . '/api/payments/initiate/');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
// Exemple d'utilisation
$api = new MovapayAPI();
$result = $api->initiatePayment(5000, 'XOF', 'Paiement pour commande #12345',
'client@example.com', '+2250701234567');
print_r($result);
?>
# 1. Obtenir le token d'accès
curl -X POST https://api.movapay.com/oauth/token/ \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=your_client_id&client_secret=your_client_secret"
# 2. Initier un paiement (remplacez YOUR_ACCESS_TOKEN par le token obtenu)
curl -X POST https://api.movapay.com/api/payments/initiate/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"currency": "XOF",
"description": "Paiement pour commande #12345",
"customer_email": "client@example.com",
"customer_phone": "+2250701234567",
"return_url": "https://votre-site.com/payment/success",
"cancel_url": "https://votre-site.com/payment/cancel"
}'
📋 Exemple de Réponse
{
"success": true,
"transaction_ref": "TXN_20241201_001",
"payment_url": "https://pay.movapay.com/payment/TXN_20241201_001",
"amount": 5000,
"currency": "XOF",
"status": "pending",
"expires_at": "2024-12-01T23:59:59Z"
}
🔍 Vérifier le Statut d'un Paiement
GET /api/payments/status/{transaction_ref}/
Récupère le statut actuel d'une transaction de paiement.
import requests
import json
# Configuration
API_BASE_URL = "https://api.movapay.com"
CLIENT_ID = "your_client_id"
CLIENT_SECRET = "your_client_secret"
# Obtenir le token d'accès
def get_access_token():
token_url = f"{API_BASE_URL}/oauth/token/"
data = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
response = requests.post(token_url, data=data)
return response.json()["access_token"]
# Vérifier le statut d'un paiement
def check_payment_status(transaction_ref):
token = get_access_token()
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
response = requests.get(
f"{API_BASE_URL}/api/payments/status/{transaction_ref}/",
headers=headers
)
return response.json()
# Exemple d'utilisation
if __name__ == "__main__":
result = check_payment_status("TXN_20241201_001")
print(json.dumps(result, indent=2))
const axios = require('axios');
// Configuration
const API_BASE_URL = 'https://api.movapay.com';
const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
// Obtenir le token d'accès
async function getAccessToken() {
try {
const response = await axios.post(`${API_BASE_URL}/oauth/token/`, {
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
});
return response.data.access_token;
} catch (error) {
console.error('Erreur lors de l\'obtention du token:', error);
throw error;
}
}
// Vérifier le statut d'un paiement
async function checkPaymentStatus(transactionRef) {
try {
const token = await getAccessToken();
const response = await axios.get(`${API_BASE_URL}/api/payments/status/${transactionRef}/`, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
return response.data;
} catch (error) {
console.error('Erreur lors de la vérification du statut:', error);
throw error;
}
}
// Exemple d'utilisation
checkPaymentStatus('TXN_20241201_001')
.then(result => console.log(result))
.catch(error => console.error(error));
// Configuration
const API_BASE_URL = 'https://api.movapay.com';
const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
// Obtenir le token d'accès
async function getAccessToken() {
try {
const response = await fetch(`${API_BASE_URL}/oauth/token/`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
})
});
const data = await response.json();
return data.access_token;
} catch (error) {
console.error('Erreur lors de l\'obtention du token:', error);
throw error;
}
}
// Vérifier le statut d'un paiement
async function checkPaymentStatus(transactionRef) {
try {
const token = await getAccessToken();
const response = await fetch(`${API_BASE_URL}/api/payments/status/${transactionRef}/`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
return await response.json();
} catch (error) {
console.error('Erreur lors de la vérification du statut:', error);
throw error;
}
}
// Exemple d'utilisation
checkPaymentStatus('TXN_20241201_001')
.then(result => console.log(result))
.catch(error => console.error(error));
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
public class MovapayAPI {
private static final String API_BASE_URL = "https://api.movapay.com";
private static final String CLIENT_ID = "your_client_id";
private static final String CLIENT_SECRET = "your_client_secret";
private static final HttpClient client = HttpClient.newHttpClient();
private static final ObjectMapper mapper = new ObjectMapper();
// Obtenir le token d'accès
public static String getAccessToken() throws Exception {
String tokenUrl = API_BASE_URL + "/oauth/token/";
String formData = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s",
CLIENT_ID, CLIENT_SECRET);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(tokenUrl))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
Map result = mapper.readValue(response.body(), Map.class);
return (String) result.get("access_token");
}
// Vérifier le statut d'un paiement
public static Map checkPaymentStatus(String transactionRef) throws Exception {
String token = getAccessToken();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(API_BASE_URL + "/api/payments/status/" + transactionRef + "/"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
return mapper.readValue(response.body(), Map.class);
}
public static void main(String[] args) {
try {
Map result = checkPaymentStatus("TXN_20241201_001");
System.out.println(mapper.writeValueAsString(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
<?php
class MovapayAPI {
private $apiBaseUrl = 'https://api.movapay.com';
private $clientId = 'your_client_id';
private $clientSecret = 'your_client_secret';
// Obtenir le token d'accès
public function getAccessToken() {
$tokenUrl = $this->apiBaseUrl . '/oauth/token/';
$postData = http_build_query([
'grant_type' => 'client_credentials',
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret
]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $tokenUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded'
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
return $data['access_token'];
}
// Vérifier le statut d'un paiement
public function checkPaymentStatus($transactionRef) {
$token = $this->getAccessToken();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->apiBaseUrl . '/api/payments/status/' . $transactionRef . '/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
// Exemple d'utilisation
$api = new MovapayAPI();
$result = $api->checkPaymentStatus('TXN_20241201_001');
print_r($result);
?>
# 1. Obtenir le token d'accès
curl -X POST https://api.movapay.com/oauth/token/ \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=your_client_id&client_secret=your_client_secret"
# 2. Vérifier le statut (remplacez YOUR_ACCESS_TOKEN par le token obtenu)
curl -X GET https://api.movapay.com/api/payments/status/TXN_20241201_001/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json"
📋 Exemple de Réponse
{
"success": true,
"transaction_ref": "TXN_20241201_001",
"status": "success",
"amount": 5000,
"currency": "XOF",
"payment_method": "wave_ci",
"customer_email": "client@example.com",
"customer_phone": "+2250701234567",
"created_at": "2024-12-01T10:30:00Z",
"paid_at": "2024-12-01T10:35:00Z",
"receipt_identifier": "REC_20241201_001"
}
🔔 Webhook/Callback
POST {votre_url_webhook}
Endpoint pour recevoir les notifications de paiement en temps réel.
from flask import Flask, request, jsonify
import json
import hmac
import hashlib
app = Flask(__name__)
# Clé secrète pour vérifier la signature (à configurer)
WEBHOOK_SECRET = "your_webhook_secret"
def verify_signature(payload, signature):
"""Vérifie la signature du webhook"""
expected_signature = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
@app.route('/webhook/payment', methods=['POST'])
def payment_webhook():
try:
# Récupérer les données
payload = request.get_data(as_text=True)
signature = request.headers.get('X-Movapay-Signature', '')
# Vérifier la signature
if not verify_signature(payload, signature):
return jsonify({'error': 'Signature invalide'}), 401
# Parser les données
data = json.loads(payload)
# Traiter la notification
transaction_ref = data.get('transaction_ref')
status = data.get('status')
amount = data.get('amount')
print(f"Notification reçue: {transaction_ref} - {status} - {amount}")
# Logique métier selon le statut
if status == 'success':
# Paiement réussi
print(f"Paiement réussi pour {transaction_ref}")
# Mettre à jour votre base de données
# Envoyer un email de confirmation
# etc.
elif status == 'failed':
# Paiement échoué
print(f"Paiement échoué pour {transaction_ref}")
# Gérer l'échec
# Notifier le client
# etc.
# Répondre avec succès
return jsonify({'status': 'received'}), 200
except Exception as e:
print(f"Erreur lors du traitement du webhook: {e}")
return jsonify({'error': 'Erreur interne'}), 500
if __name__ == '__main__':
app.run(debug=True, port=5000)
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
import json
import hmac
import hashlib
# Clé secrète pour vérifier la signature
WEBHOOK_SECRET = "your_webhook_secret"
def verify_signature(payload, signature):
"""Vérifie la signature du webhook"""
expected_signature = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
@csrf_exempt
@require_http_methods(["POST"])
def payment_webhook(request):
try:
# Récupérer les données
payload = request.body.decode('utf-8')
signature = request.headers.get('X-Movapay-Signature', '')
# Vérifier la signature
if not verify_signature(payload, signature):
return JsonResponse({'error': 'Signature invalide'}, status=401)
# Parser les données
data = json.loads(payload)
# Traiter la notification
transaction_ref = data.get('transaction_ref')
status = data.get('status')
amount = data.get('amount')
print(f"Notification reçue: {transaction_ref} - {status} - {amount}")
# Logique métier selon le statut
if status == 'success':
# Paiement réussi
print(f"Paiement réussi pour {transaction_ref}")
# Mettre à jour votre base de données
# Envoyer un email de confirmation
# etc.
elif status == 'failed':
# Paiement échoué
print(f"Paiement échoué pour {transaction_ref}")
# Gérer l'échec
# Notifier le client
# etc.
# Répondre avec succès
return JsonResponse({'status': 'received'}, status=200)
except Exception as e:
print(f"Erreur lors du traitement du webhook: {e}")
return JsonResponse({'error': 'Erreur interne'}, status=500)
const express = require('express');
const crypto = require('crypto');
const app = express();
// Middleware pour parser le JSON
app.use(express.json({ verify: (req, res, buf) => {
req.rawBody = buf;
}}));
// Clé secrète pour vérifier la signature
const WEBHOOK_SECRET = 'your_webhook_secret';
function verifySignature(payload, signature) {
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhook/payment', (req, res) => {
try {
const payload = req.rawBody.toString();
const signature = req.headers['x-movapay-signature'] || '';
// Vérifier la signature
if (!verifySignature(payload, signature)) {
return res.status(401).json({ error: 'Signature invalide' });
}
// Les données sont déjà parsées dans req.body
const data = req.body;
// Traiter la notification
const transactionRef = data.transaction_ref;
const status = data.status;
const amount = data.amount;
console.log(`Notification reçue: ${transactionRef} - ${status} - ${amount}`);
// Logique métier selon le statut
if (status === 'success') {
// Paiement réussi
console.log(`Paiement réussi pour ${transactionRef}`);
// Mettre à jour votre base de données
// Envoyer un email de confirmation
// etc.
} else if (status === 'failed') {
// Paiement échoué
console.log(`Paiement échoué pour ${transactionRef}`);
// Gérer l'échec
// Notifier le client
// etc.
}
// Répondre avec succès
res.status(200).json({ status: 'received' });
} catch (error) {
console.error('Erreur lors du traitement du webhook:', error);
res.status(500).json({ error: 'Erreur interne' });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Serveur webhook démarré sur le port ${PORT}`);
});
<?php
// Clé secrète pour vérifier la signature
$WEBHOOK_SECRET = 'your_webhook_secret';
// Récupérer les données
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_MOVAPAY_SIGNATURE'] ?? '';
// Vérifier la signature
function verifySignature($payload, $signature, $secret) {
$expectedSignature = hash_hmac('sha256', $payload, $secret);
return hash_equals($expectedSignature, $signature);
}
if (!verifySignature($payload, $signature, $WEBHOOK_SECRET)) {
http_response_code(401);
echo json_encode(['error' => 'Signature invalide']);
exit;
}
// Parser les données
$data = json_decode($payload, true);
// Traiter la notification
$transactionRef = $data['transaction_ref'] ?? '';
$status = $data['status'] ?? '';
$amount = $data['amount'] ?? '';
error_log("Notification reçue: $transactionRef - $status - $amount");
// Logique métier selon le statut
if ($status === 'success') {
// Paiement réussi
error_log("Paiement réussi pour $transactionRef");
// Mettre à jour votre base de données
// Envoyer un email de confirmation
// etc.
} elseif ($status === 'failed') {
// Paiement échoué
error_log("Paiement échoué pour $transactionRef");
// Gérer l'échec
// Notifier le client
// etc.
}
// Répondre avec succès
http_response_code(200);
header('Content-Type: application/json');
echo json_encode(['status' => 'received']);
?>
<?php
/*
Plugin Name: Movapay Webhook Handler
Description: Gère les webhooks de paiement Movapay
Version: 1.0
*/
// Clé secrète pour vérifier la signature
define('MOVAPAY_WEBHOOK_SECRET', 'your_webhook_secret');
// Ajouter l'action pour le webhook
add_action('init', 'handle_movapay_webhook');
function handle_movapay_webhook() {
// Vérifier si c'est notre endpoint webhook
if ($_SERVER['REQUEST_URI'] === '/wp-json/movapay/webhook') {
// Vérifier la méthode HTTP
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit;
}
// Récupérer les données
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_MOVAPAY_SIGNATURE'] ?? '';
// Vérifier la signature
if (!verify_movapay_signature($payload, $signature)) {
http_response_code(401);
echo json_encode(['error' => 'Signature invalide']);
exit;
}
// Parser les données
$data = json_decode($payload, true);
// Traiter la notification
$transactionRef = $data['transaction_ref'] ?? '';
$status = $data['status'] ?? '';
$amount = $data['amount'] ?? '';
error_log("Movapay webhook: $transactionRef - $status - $amount");
// Logique métier selon le statut
if ($status === 'success') {
// Paiement réussi
handle_successful_payment($data);
} elseif ($status === 'failed') {
// Paiement échoué
handle_failed_payment($data);
}
// Répondre avec succès
http_response_code(200);
header('Content-Type: application/json');
echo json_encode(['status' => 'received']);
exit;
}
}
function verify_movapay_signature($payload, $signature) {
$expectedSignature = hash_hmac('sha256', $payload, MOVAPAY_WEBHOOK_SECRET);
return hash_equals($expectedSignature, $signature);
}
function handle_successful_payment($data) {
// Exemple: Mettre à jour une commande WooCommerce
$transactionRef = $data['transaction_ref'];
// Chercher la commande par référence
$orders = wc_get_orders([
'meta_key' => '_movapay_transaction_ref',
'meta_value' => $transactionRef,
'limit' => 1
]);
if (!empty($orders)) {
$order = $orders[0];
$order->update_status('completed', 'Paiement Movapay confirmé');
$order->add_order_note("Paiement Movapay réussi: $transactionRef");
}
// Envoyer un email de confirmation
$customerEmail = $data['customer_email'] ?? '';
if ($customerEmail) {
wp_mail($customerEmail, 'Paiement confirmé', 'Votre paiement a été confirmé avec succès.');
}
}
function handle_failed_payment($data) {
$transactionRef = $data['transaction_ref'];
error_log("Paiement échoué: $transactionRef");
// Notifier l'administrateur
wp_mail(get_option('admin_email'), 'Paiement échoué', "Paiement échoué pour: $transactionRef");
}
// Ajouter l'endpoint REST API
add_action('rest_api_init', function () {
register_rest_route('movapay/v1', '/webhook', [
'methods' => 'POST',
'callback' => 'handle_movapay_webhook',
'permission_callback' => '__return_true'
]);
});
?>
📋 Exemple de Données Webhook
{
"transaction_ref": "TXN_20241201_001",
"status": "success",
"amount": "5000",
"amount_with_fees": "5000",
"currency": "XOF",
"provider_reference": "WAVE_123456789",
"receipt_identifier": "REC_20241201_001",
"payment_method": "wave_ci",
"customer_phone": "+2250701234567",
"customer_email": "client@example.com",
"created_at": "2024-12-01T10:30:00Z",
"integration_id": "INT_001"
}
📚 Informations Supplémentaires
Codes d'erreur, bonnes pratiques et exemples d'intégration.
🚨 Codes d'Erreur
{
"error": "400 Bad Request",
"message": "Données invalides",
"details": {
"amount": ["Ce champ est requis"],
"currency": ["Devise non supportée"]
}
}
{
"error": "401 Unauthorized",
"message": "Token d'accès invalide ou expiré"
}
{
"error": "403 Forbidden",
"message": "Accès refusé - Vérifiez vos permissions"
}
{
"error": "404 Not Found",
"message": "Transaction non trouvée"
}
{
"error": "429 Too Many Requests",
"message": "Limite de requêtes dépassée"
}
{
"error": "500 Internal Server Error",
"message": "Erreur interne du serveur"
}
✅ Bonnes Pratiques
- Sécurité : Stockez toujours vos identifiants de manière sécurisée (variables d'environnement)
- Gestion d'erreurs : Implémentez une gestion robuste des erreurs dans votre application
- Webhooks : Configurez votre URL de callback et testez-la en mode développement
- Vérification : Vérifiez toujours la signature des webhooks pour éviter les attaques
- Logs : Gardez des logs détaillés de toutes les transactions
- Test : Testez d'abord en mode sandbox avant de passer en production
- Montants : Utilisez des types décimaux pour les calculs financiers
- Idempotence : Gérez les doublons de webhooks
🔗 Exemples d'Intégration
E-commerce (WooCommerce)
// Dans functions.php de votre thème WordPress
add_action('woocommerce_payment_complete', 'handle_movapay_payment');
function handle_movapay_payment($order_id) {
$order = wc_get_order($order_id);
$payment_method = $order->get_payment_method();
if ($payment_method === 'movapay') {
// Traitement spécifique Movapay
$transaction_ref = get_post_meta($order_id, '_movapay_transaction_ref', true);
// Vérifier le statut du paiement
$status = check_movapay_payment_status($transaction_ref);
if ($status === 'success') {
$order->update_status('completed', 'Paiement Movapay confirmé');
}
}
}
Application Mobile (React Native)
import axios from 'axios';
const MovapayAPI = {
baseURL: 'https://api.movapay.com',
async initiatePayment(amount, description) {
try {
const token = await this.getAccessToken();
const response = await axios.post(
`${this.baseURL}/api/payments/initiate/`,
{
amount: amount,
description: description,
return_url: 'myapp://payment/success',
cancel_url: 'myapp://payment/cancel'
},
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
// Ouvrir l'URL de paiement dans le navigateur
Linking.openURL(response.data.payment_url);
return response.data;
} catch (error) {
console.error('Erreur paiement:', error);
throw error;
}
}
};
Application Web (Vue.js)
<template>
<div>
<button @click="initiatePayment" :disabled="loading">
{{ loading ? 'Chargement...' : 'Payer' }}
</button>
</div>
</template>
<script>
export default {
data() {
return {
loading: false
}
},
methods: {
async initiatePayment() {
this.loading = true;
try {
const response = await this.$http.post('/api/payments/initiate/', {
amount: 5000,
description: 'Commande #12345',
return_url: window.location.origin + '/payment/success',
cancel_url: window.location.origin + '/payment/cancel'
});
// Rediriger vers la page de paiement
window.location.href = response.data.payment_url;
} catch (error) {
console.error('Erreur:', error);
this.$toast.error('Erreur lors de l\'initiation du paiement');
} finally {
this.loading = false;
}
}
}
}
</script>
🆘 Support
Besoin d'aide pour intégrer l'API Movapay ?
- Documentation : Consultez notre documentation complète
- Support technique : Contactez-nous à support@movapay.com
- Communauté : Rejoignez notre communauté de développeurs
- Status API : Vérifiez le statut de nos services