Introduction
L'API UnitechPay permet d'intégrer les paiements Wave et Orange Money dans vos applications. Elle gère également les retraits et les webhooks pour une expérience complète.
URL de base: https://api.unitech.sn/
Fonctionnalités
- Paiements sécurisés via Wave et Orange Money
- 3 options Orange Money: QR Code, Max It, et Orange Money
- Génération de QR Codes Orange Money
- URLs de redirection personnalisables pour tous les paiements
- Retraits automatiques vers Wave, Orange Money ou comptes bancaires
- Webhooks pour les notifications en temps réel
- Plugin WordPress officiel disponible
- API RESTful avec authentification par clé API
Authentification
Toutes les requêtes à l'API doivent inclure un header d'authentification avec votre clé API.
Authorization: Bearer VOTRE_CLE_API
Obtenir une clé API
Pour obtenir une clé API, vous devez créer un compte marchand sur notre plateforme. Une fois connecté, vous pourrez générer une clé API depuis votre tableau de bord.
Important: Gardez votre clé API secrète et ne la partagez jamais publiquement.
Endpoints
| Méthode | Endpoint | Description |
|---|---|---|
| POST | /api.php?action=create_wave_payment | Créer un paiement Wave avec URLs de redirection |
| POST | /api.php?action=create_orange_qr | Générer un QR Code Orange Money |
| POST | /api.php?action=create_orange_maxit | Créer un paiement Max It avec callbacks |
| POST | /api.php?action=create_orange_om | Créer un paiement Orange Money standard |
| POST | /api.php?action=withdraw_funds | Demander un retrait automatique |
| POST | /api.php?action=configure_webhook | Configurer les webhooks |
| GET | /api.php?action=balance | Consulter le solde disponible |
| GET | /api.php?action=transactions | Lister les transactions |
| GET | /api.php?action=withdrawals | Lister les retraits |
Paiements Wave
Créer un paiement Wave
Paramètres
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| amount | number | Oui | Montant du paiement en XOF |
| customer_number | string | Oui | Numéro de téléphone du client |
| description | string | Non | Description du paiement |
| callback_success | string | Non | URL de redirection après succès |
| callback_cancel | string | Non | URL de redirection après annulation |
Exemple de requête
{
"amount": 5000,
"customer_number": "771234567",
"description": "Paiement pour 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_123456",
"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"
}
}
}
URLs de redirection: Si non spécifiées, les URLs par défaut seront utilisées. Après paiement, l'utilisateur sera automatiquement redirigé vers l'URL appropriée.
Paiements Orange Money
QR Code
Génération de QR Code pour paiements mobiles avec callbacks personnalisés
POST/api.php?action=create_orange_qr
Max It
Paiement via l'application Max It avec redirection automatique
POST/api.php?action=create_orange_maxit
Orange Money
Paiement standard Orange Money avec callbacks
POST/api.php?action=create_orange_om
1. Générer un QR Code Orange Money
Paramètres
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| amount | number | Oui | Montant du paiement en XOF |
| reference | string | Non | Référence personnalisée |
| description | string | Non | Description du paiement |
| callback_success | string | Non | URL de redirection après succès |
| callback_cancel | string | Non | URL de redirection après annulation |
Exemple de requête
{
"amount": 5000,
"reference": "commande_123",
"description": "Paiement pour 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": "commande_123",
"qr_code": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...",
"deep_links": {
"MAXIT": "https://sugu.orange-sonatel.com/np/dgjuu_XudhPKI1D4zud",
"OM": "https://orangenonevsn.page.link/zzzubAUuJ7tX5uNK6"
},
"amount": 5000,
"status": "pending",
"type": "qr_code",
"validity": 300,
"callback_urls": {
"success": "https://monsite.com/payment/success",
"cancel": "https://monsite.com/payment/cancel"
}
}
}
Note: Le QR Code est retourné sous forme de données base64 encodées (data URI) qui peuvent être directement utilisées dans les balises <img>. Les URLs de callback permettent de rediriger automatiquement l'utilisateur après le paiement.
2. Créer un paiement Max It
Paramètres
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| amount | number | Oui | Montant du paiement en XOF |
| customer_number | string | Oui | Numéro de téléphone du client |
| description | string | Non | Description du paiement |
| callback_success | string | Non | URL de redirection après succès |
| callback_cancel | string | Non | URL de redirection après annulation |
Exemple de requête
{
"amount": 5000,
"customer_number": "771234567",
"description": "Paiement pour commande #123",
"callback_success": "https://monsite.com/payment/success",
"callback_cancel": "https://monsite.com/payment/cancel"
}
Réponse
{
"success": true,
"data": {
"transaction_id": 2,
"reference": "orange_maxit_123456",
"payment_url": "https://sugu.orange-sonatel.com/np/dgjuu_XudhPKI1D4zud",
"deep_links": {
"MAXIT": "https://sugu.orange-sonatel.com/np/dgjuu_XudhPKI1D4zud",
"OM": "https://orangenonevsn.page.link/zzzubAUuJ7tX5uNK6"
},
"amount": 5000,
"status": "pending",
"type": "maxit",
"callback_urls": {
"success": "https://monsite.com/payment/success",
"cancel": "https://monsite.com/payment/cancel"
}
}
}
3. Créer un paiement Orange Money
Paramètres
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| amount | number | Oui | Montant du paiement en XOF |
| customer_number | string | Oui | Numéro de téléphone du client |
| description | string | Non | Description du paiement |
| callback_success | string | Non | URL de redirection après succès |
| callback_cancel | string | Non | URL de redirection après annulation |
Exemple de requête
{
"amount": 5000,
"customer_number": "771234567",
"description": "Paiement pour commande #123",
"callback_success": "https://monsite.com/payment/success",
"callback_cancel": "https://monsite.com/payment/cancel"
}
Réponse
{
"success": true,
"data": {
"transaction_id": 3,
"reference": "orange_om_123456",
"payment_url": "https://orangenonevsn.page.link/zzzubAUuJ7tX5uNK6",
"deep_links": {
"MAXIT": "https://sugu.orange-sonatel.com/np/dgjuu_XudhPKI1D4zud",
"OM": "https://orangenonevsn.page.link/zzzubAUuJ7tX5uNK6"
},
"amount": 5000,
"status": "pending",
"type": "orange_money",
"callback_urls": {
"success": "https://monsite.com/payment/success",
"cancel": "https://monsite.com/payment/cancel"
}
}
}
Retraits automatiques
Le système de retrait automatique permet de transférer instantanément vos fonds vers vos comptes Wave, Orange Money ou bancaires avec commission de 1.5%.
Demander un retrait
Paramètres
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| amount | number | Oui | Montant à retirer en XOF |
| method | string | Oui | Méthode de retrait (wave, orange, bank) |
| account | string | Oui | Numéro de compte ou téléphone destinataire |
Exemple de requête
{
"amount": 10000,
"method": "wave",
"account": "771234567"
}
Réponse
{
"success": true,
"data": {
"withdrawal_id": 1,
"reference": "WDR_1_1671234567_9876",
"amount": 10000,
"commission": 150,
"net_amount": 9850,
"method": "wave",
"status": "processed"
}
}
Délais de traitement:
• Wave & Orange Money: Instantané (automatique)
• Virement bancaire: 3 à 5 jours ouvrés (traitement manuel)
Webhooks
Les webhooks permettent de recevoir des notifications en temps réel sur les événements de votre compte.
Configurer les webhooks
Paramètres
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| webhook_url | string | Oui | URL de votre endpoint webhook (HTTPS requis) |
| events | array | Non | Événements à écouter (tous par défaut) |
Événements disponibles
payment_completed- Paiement réussi et fonds créditéspayment_failed- Paiement échouépayment_expired- Paiement expiré (timeout)withdrawal_processed- Retrait traité avec succèswithdrawal_failed- Retrait échoué
Exemple de payload webhook
{
"event": "payment_completed",
"transaction_id": 1,
"reference": "wave_123456",
"amount": 5000,
"status": "completed",
"method": "wave",
"commission": 75,
"net_amount": 4925,
"timestamp": 1684146600,
"signature": "hmac_sha256_signature_for_verification"
}
Sécurité: Vérifiez toujours la signature HMAC-SHA256 des webhooks en utilisant votre clé API comme secret. Cela garantit l'authenticité des notifications.
Plugins & Intégrations
UnitechPay propose plusieurs solutions d'intégration prêtes à l'emploi pour faciliter l'intégration des paiements mobile money dans vos projets.
Plugin WordPress Officiel
Intégrez facilement les paiements Wave et Orange Money dans votre site WordPress ou boutique WooCommerce avec notre plugin officiel.
Fonctionnalités:
- ✅ Compatible WooCommerce
- ✅ Paiements Wave et Orange Money
- ✅ Webhooks intégrés
Avantages:
- 🚀 Installation en 1 clic
- 🔧 Configuration simplifiée
- 📱 Interface responsive
- 🔄 Mises à jour automatiques
Guide d'installation WordPress
Installation
Téléchargez le plugin depuis le répertoire WordPress officiel ou installez-le directement depuis votre administration WordPress (Extensions > Ajouter > Rechercher "UnitechPay").
Configuration
Allez dans "UnitechPay Settings" dans votre menu WordPress et configurez:
- • Entrez votre numéro Wave et Orange Money
- • Les options de paiement (Wave/Orange Money)
Activation WooCommerce
Si vous utilisez WooCommerce, activez "UnitechPay" comme méthode de paiement dans WooCommerce > Réglages > Paiements.
Intégrations à venir
Shopify App
Bientôt disponible
PrestaShop Module
En développement
Magento Extension
Prévu Q2 2025
Codes d'erreur
| Code HTTP | Message | Description |
|---|---|---|
| 200 | Success | Requête traitée avec succès |
| 400 | Bad Request | Paramètres manquants ou invalides |
| 401 | Unauthorized | Clé API manquante ou invalide |
| 404 | Not Found | Endpoint ou ressource non trouvée |
| 500 | Internal Server Error | Erreur interne du serveur |
Exemples d'intégration
PHP - Paiement Wave avec callbacks
<?php
$api_url = 'https://api.unitech.sn/api.php';
$api_key = 'votre_cle_api';
// Créer un paiement Wave avec URLs de redirection
$data = [
'amount' => 5000,
'customer_number' => '771234567',
'description' => 'Paiement pour commande #123',
'callback_success' => 'https://monsite.com/payment/success',
'callback_cancel' => 'https://monsite.com/payment/cancel'
];
$ch = curl_init($api_url . '?action=create_wave_payment');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $api_key,
'Content-Type: application/json'
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result = json_decode($response, true);
if ($http_code === 200 && $result['success']) {
// Rediriger vers le lien de paiement Wave
header('Location: ' . $result['data']['payment_url']);
exit;
} else {
echo 'Erreur: ' . ($result['message'] ?? 'Erreur inconnue');
}
?>
PHP - Paiement Orange Money QR Code
<?php
// Générer un QR Code Orange Money
$data = [
'amount' => 2500,
'reference' => 'commande_' . uniqid(),
'description' => 'Paiement QR Code',
'callback_success' => 'https://monsite.com/success',
'callback_cancel' => 'https://monsite.com/cancel'
];
$ch = curl_init($api_url . '?action=create_orange_qr');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $api_key,
'Content-Type: application/json'
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data)
]);
$response = curl_exec($ch);
$result = json_decode($response, true);
if ($result['success']) {
$qr_code = $result['data']['qr_code'];
echo '<img src="' . $qr_code . '" alt="QR Code Orange Money" />';
echo '<p>Montant: ' . number_format($result['data']['amount']) . ' XOF</p>';
echo '<p>Référence: ' . $result['data']['reference'] . '</p>';
} else {
echo 'Erreur: ' . $result['message'];
}
?>
Node.js - Paiement complet avec callbacks
const axios = require('axios');
const API_URL = 'https://api.unitech.sn/api.php';
const API_KEY = 'votre_cle_api';
class UnitechPayAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseURL = API_URL;
}
async createWavePayment(amount, customerNumber, description, callbacks = {}) {
const data = {
amount,
customer_number: customerNumber,
description,
callback_success: callbacks.success || 'https://monsite.com/success',
callback_cancel: callbacks.cancel || 'https://monsite.com/cancel'
};
try {
const response = await axios.post(
`${this.baseURL}?action=create_wave_payment`,
data,
{
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
timeout: 30000
}
);
return response.data;
} catch (error) {
console.error('Erreur API UnitechPay:', error.message);
throw error;
}
}
async createOrangeQR(amount, reference, description, callbacks = {}) {
const data = {
amount,
reference,
description,
callback_success: callbacks.success,
callback_cancel: callbacks.cancel
};
try {
const response = await axios.post(
`${this.baseURL}?action=create_orange_qr`,
data,
{
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
}
}
);
if (response.data.success) {
const qrCode = response.data.data.qr_code;
console.log('QR Code généré:', qrCode.substring(0, 50) + '...');
return response.data;
} else {
throw new Error(response.data.message);
}
} catch (error) {
console.error('Erreur QR Code:', error.message);
throw error;
}
}
async withdrawFunds(amount, method, account) {
const data = { amount, method, account };
try {
const response = await axios.post(
`${this.baseURL}?action=withdraw_funds`,
data,
{
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
} catch (error) {
console.error('Erreur retrait:', error.message);
throw error;
}
}
}
// Utilisation
const unitechPay = new UnitechPayAPI(API_KEY);
// Exemple 1: Paiement Wave
unitechPay.createWavePayment(5000, '771234567', 'Test paiement', {
success: 'https://monapp.com/payment/success',
cancel: 'https://monapp.com/payment/cancel'
})
.then(result => {
console.log('Paiement Wave créé:', result.data.payment_url);
})
.catch(error => {
console.error('Erreur:', error.message);
});
// Exemple 2: QR Code Orange Money
unitechPay.createOrangeQR(2500, 'cmd_123', 'Achat produit')
.then(result => {
console.log('QR Code créé, référence:', result.data.reference);
})
.catch(error => {
console.error('Erreur QR:', error.message);
});
Python - Classe complète UnitechPay
import requests
import json
from typing import Dict, Optional, Any
from dataclasses import dataclass
@dataclass
class CallbackURLs:
success: Optional[str] = None
cancel: Optional[str] = None
class UnitechPayAPI:
def __init__(self, api_key: str, base_url: str = "https://api.unitech.sn/api.php"):
self.api_key = api_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
})
def _make_request(self, action: str, data: Dict[str, Any]) -> Dict[str, Any]:
"""Effectuer une requête à l'API"""
try:
response = self.session.post(
f"{self.base_url}?action={action}",
json=data,
timeout=30
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"Erreur API: {e}")
def create_wave_payment(
self,
amount: float,
customer_number: str,
description: str = "",
callbacks: Optional[CallbackURLs] = None
) -> Dict[str, Any]:
"""Créer un paiement Wave avec callbacks"""
data = {
"amount": amount,
"customer_number": customer_number,
"description": description
}
if callbacks:
if callbacks.success:
data["callback_success"] = callbacks.success
if callbacks.cancel:
data["callback_cancel"] = callbacks.cancel
result = self._make_request("create_wave_payment", data)
if not result.get("success"):
raise Exception(f"Erreur Wave: {result.get('message', 'Erreur inconnue')}")
return result
def create_orange_qr(
self,
amount: float,
reference: Optional[str] = None,
description: str = "",
callbacks: Optional[CallbackURLs] = None
) -> Dict[str, Any]:
"""Générer un QR Code Orange Money"""
data = {
"amount": amount,
"description": description
}
if reference:
data["reference"] = reference
if callbacks:
if callbacks.success:
data["callback_success"] = callbacks.success
if callbacks.cancel:
data["callback_cancel"] = callbacks.cancel
result = self._make_request("create_orange_qr", data)
if not result.get("success"):
raise Exception(f"Erreur QR Code: {result.get('message', 'Erreur inconnue')}")
return result
def create_orange_maxit(
self,
amount: float,
customer_number: str,
description: str = "",
callbacks: Optional[CallbackURLs] = None
) -> Dict[str, Any]:
"""Créer un paiement Max It"""
data = {
"amount": amount,
"customer_number": customer_number,
"description": description
}
if callbacks:
if callbacks.success:
data["callback_success"] = callbacks.success
if callbacks.cancel:
data["callback_cancel"] = callbacks.cancel
result = self._make_request("create_orange_maxit", data)
if not result.get("success"):
raise Exception(f"Erreur Max It: {result.get('message', 'Erreur inconnue')}")
return result
def withdraw_funds(self, amount: float, method: str, account: str) -> Dict[str, Any]:
"""Demander un retrait"""
data = {
"amount": amount,
"method": method, # wave, orange, bank
"account": account
}
result = self._make_request("withdraw_funds", data)
if not result.get("success"):
raise Exception(f"Erreur retrait: {result.get('message', 'Erreur inconnue')}")
return result
def get_balance(self) -> Dict[str, Any]:
"""Consulter le solde"""
return self._make_request("balance", {})
# Exemple d'utilisation
if __name__ == "__main__":
# Initialiser l'API
api = UnitechPayAPI("votre_cle_api")
try:
# Créer des URLs de callback
callbacks = CallbackURLs(
success="https://monsite.com/success",
cancel="https://monsite.com/cancel"
)
# Créer un paiement Wave
wave_payment = api.create_wave_payment(
amount=5000,
customer_number="771234567",
description="Paiement test",
callbacks=callbacks
)
print(f"Paiement Wave: {wave_payment['data']['payment_url']}")
# Générer un QR Code Orange Money
qr_payment = api.create_orange_qr(
amount=2500,
reference="test_qr_123",
description="Paiement QR Code",
callbacks=callbacks
)
print(f"QR Code généré: {qr_payment['data']['reference']}")
# Consulter le solde
balance = api.get_balance()
print(f"Solde actuel: {balance['data']['balance']} XOF")
# Effectuer un retrait
withdrawal = api.withdraw_funds(
amount=1000,
method="wave",
account="771234567"
)
print(f"Retrait effectué: {withdrawal['data']['net_amount']} XOF net")
except Exception as e:
print(f"Erreur: {e}")
Flutter/Dart - Intégration complète avec callbacks
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter/material.dart';
class CallbackUrls {
final String? success;
final String? cancel;
CallbackUrls({this.success, this.cancel});
Map<String, dynamic> toMap() {
final map = <String, dynamic>{};
if (success != null) map['callback_success'] = success;
if (cancel != null) map['callback_cancel'] = cancel;
return map;
}
}
class UnitechPayAPI {
static const String baseUrl = 'https://api.unitech.sn/api.php';
final String apiKey;
UnitechPayAPI(this.apiKey);
Future<Map<String, dynamic>> _makeRequest(
String action,
Map<String, dynamic> data
) async {
try {
final response = await http.post(
Uri.parse('$baseUrl?action=$action'),
headers: {
'Authorization': 'Bearer $apiKey',
'Content-Type': 'application/json',
},
body: json.encode(data),
).timeout(const Duration(seconds: 30));
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('HTTP ${response.statusCode}: ${response.body}');
}
} catch (e) {
throw Exception('Erreur réseau: $e');
}
}
Future<Map<String, dynamic>> createWavePayment({
required double amount,
required String customerNumber,
String? description,
CallbackUrls? callbacks,
}) async {
final data = {
'amount': amount,
'customer_number': customerNumber,
if (description != null) 'description': description,
if (callbacks != null) ...callbacks.toMap(),
};
final result = await _makeRequest('create_wave_payment', data);
if (result['success'] != true) {
throw Exception(result['message'] ?? 'Erreur Wave inconnue');
}
return result;
}
Future<Map<String, dynamic>> createOrangeQR({
required double amount,
String? reference,
String? description,
CallbackUrls? callbacks,
}) async {
final data = {
'amount': amount,
if (reference != null) 'reference': reference,
if (description != null) 'description': description,
if (callbacks != null) ...callbacks.toMap(),
};
final result = await _makeRequest('create_orange_qr', data);
if (result['success'] != true) {
throw Exception(result['message'] ?? 'Erreur QR Code inconnue');
}
return result;
}
Future<Map<String, dynamic>> createOrangeMaxIt({
required double amount,
required String customerNumber,
String? description,
CallbackUrls? callbacks,
}) async {
final data = {
'amount': amount,
'customer_number': customerNumber,
if (description != null) 'description': description,
if (callbacks != null) ...callbacks.toMap(),
};
final result = await _makeRequest('create_orange_maxit', data);
if (result['success'] != true) {
throw Exception(result['message'] ?? 'Erreur Max It inconnue');
}
return result;
}
Future<Map<String, dynamic>> withdrawFunds({
required double amount,
required String method,
required String account,
}) async {
final data = {
'amount': amount,
'method': method,
'account': account,
};
final result = await _makeRequest('withdraw_funds', data);
if (result['success'] != true) {
throw Exception(result['message'] ?? 'Erreur retrait inconnue');
}
return result;
}
}
// Widget exemple d'utilisation
class PaymentWidget extends StatefulWidget {
@override
_PaymentWidgetState createState() => _PaymentWidgetState();
}
class _PaymentWidgetState extends State<PaymentWidget> {
final UnitechPayAPI api = UnitechPayAPI('votre_cle_api');
bool isLoading = false;
Future<void> createWavePayment() async {
setState(() { isLoading = true; });
try {
final callbacks = CallbackUrls(
success: 'https://monapp.com/success',
cancel: 'https://monapp.com/cancel',
);
final result = await api.createWavePayment(
amount: 5000,
customerNumber: '771234567',
description: 'Paiement test Flutter',
callbacks: callbacks,
);
final paymentUrl = result['data']['payment_url'];
print('URL de paiement: $paymentUrl');
// Rediriger vers le navigateur
// await launchUrlString(paymentUrl);
} catch (e) {
print('Erreur: $e');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Erreur: $e')),
);
} finally {
setState(() { isLoading = false; });
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('UnitechPay Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: isLoading ? null : createWavePayment,
child: isLoading
? CircularProgressIndicator()
: Text('Payer avec Wave'),
),
],
),
),
);
}
}