Semoa Integration with EasySwitch¶
Overview¶
Semoa is a payment aggregator serving West Africa (UEMOA zone). It provides a direct API model for mobile money payments. EasySwitch wraps the Semoa API with automatic authentication (token retrieval) behind a unified interface.
Prerequisites¶
- EasySwitch installed (see Installation)
- A Semoa merchant account with API credentials
- Your API key, Client ID, Client Secret, Username, and Password
Supported Features¶
| Feature | Semoa Support |
|---|---|
| Payment | ✅ via send_payment() |
| Transaction Status | ✅ via check_status() |
| Transaction Details | ⚠️ via get_transaction_detail() (falls back to status data) |
| Cancellation | ✅ via cancel_transaction() |
| Refunds | ❌ Not supported |
| Webhook Validation | ⚠️ Basic validation (enhance with your own signature logic) |
Supported Currencies¶
| Currency | Code | Min | Max |
|---|---|---|---|
| CFA Franc (BCEAO) | XOF |
100.00 | 1,000,000 |
| CFA Franc (BEAC) | XAF |
100.00 | 1,000,000 |
| Euro | EUR |
1.00 | 10,000 |
| US Dollar | USD |
1.00 | 10,000 |
Setup¶
Minimal Configuration¶
from easyswitch import EasySwitch, Provider
config = {
"providers": {
"SEMOA": {
"api_key": "your_semoa_api_key",
"callback_url": "https://your-site.com/webhook/semoa",
"environment": "sandbox",
"extra": {
"client_id": "your_client_id",
"client_secret": "your_client_secret",
"username": "your_username",
"password": "your_password",
}
}
},
"default_provider": "SEMOA",
}
client = EasySwitch.from_dict(config)
Important: The SDK automatically authenticates on first request. No manual token handling is needed.
Environment Variables (.env)¶
EASYSWITCH_ENABLED_PROVIDERS=semoa
EASYSWITCH_DEFAULT_PROVIDER=semoa
EASYSWITCH_SEMOA_API_KEY=your_semoa_api_key
EASYSWITCH_SEMOA_X_CLIENT_ID=your_client_id
EASYSWITCH_SEMOA_X_CLIENT_SECRET=your_client_secret
EASYSWITCH_SEMOA_X_USERNAME=your_username
EASYSWITCH_SEMOA_X_PASSWORD=your_password
EASYSWITCH_SEMOA_CALLBACK_URL=https://your-site.com/webhook/semoa
EASYSWITCH_SEMOA_ENVIRONMENT=sandbox
client = EasySwitch.from_env()
API Methods¶
1. Send Payment¶
Semoa uses a direct API model: calling send_payment() sends the payment request and returns a payment link if available.
from easyswitch import (
TransactionDetail, Currency, TransactionStatus,
TransactionType, CustomerInfo
)
transaction = TransactionDetail(
transaction_id="order-20240704-001",
amount=5000.00,
currency=Currency.XOF,
customer=CustomerInfo(
phone_number="+22890123456",
first_name="John",
last_name="Doe",
),
reason="Payment for invoice INV-2024-07",
callback_url="https://your-site.com/webhook/semoa",
)
response = client.send_payment(transaction)
print(f"Transaction ID: {response.transaction_id}")
print(f"Payment URL: {response.payment_link}")
print(f"Status: {response.status}")
2. Check Transaction Status¶
status_response = client.check_status("order-20240704-001")
print(f"Status: {status_response.status}")
print(f"Amount: {status_response.amount}")
if status_response.status == TransactionStatus.SUCCESSFUL:
print("Payment completed!")
elif status_response.status == TransactionStatus.FAILED:
print("Payment failed")
3. Cancel a Transaction¶
Semoa supports transaction cancellation via the API:
cancelled = client.cancel_transaction("order-20240704-001")
if cancelled:
print("Transaction successfully cancelled")
else:
print("Cancellation failed")
4. Get Transaction Details¶
detail = client.get_transaction_detail("order-20240704-001")
print(f"Amount: {detail.amount}")
print(f"Status: {detail.status}")
Webhook Management¶
Semoa's webhook signature verification is not fully documented. EasySwitch provides a pass-through validation that accepts all webhooks. For production, implement custom signature verification.
from flask import Flask, request, jsonify
app = Flask(__name__)
client = EasySwitch.from_env()
@app.route("/webhook/semoa", methods=["POST"])
def semoa_webhook():
payload = request.get_json()
headers = dict(request.headers)
event = client.parse_webhook(
payload=payload,
headers=headers,
)
if event.status == TransactionStatus.SUCCESSFUL:
print(f"Payment {event.transaction_id} confirmed")
# Fulfill order…
return jsonify({"status": "ok"}), 200
Status Mapping¶
| Semoa Status | EasySwitch Status | Meaning |
|---|---|---|
PENDING |
PENDING |
Awaiting processing |
SUCCESSFUL / SUCCESS |
SUCCESSFUL |
Payment completed |
FAILED / FAIL |
FAILED |
Payment failed |
CANCELLED / CANCEL |
CANCELLED |
Cancelled |
EXPIRED |
EXPIRED |
Payment expired |
ERROR |
ERROR |
Technical error |
Complete Example¶
from easyswitch import (
EasySwitch, TransactionDetail, Currency,
TransactionStatus, CustomerInfo,
)
from easyswitch.exceptions import PaymentError
client = EasySwitch.from_env()
tx = TransactionDetail(
transaction_id="demo-001",
amount=3500.00,
currency=Currency.XOF,
customer=CustomerInfo(
phone_number="+22890123456",
first_name="Demo",
last_name="User",
),
reason="Test payment via Semoa",
)
try:
response = client.send_payment(tx)
print(f"Payment sent. Status: {response.status}")
# Check status after a few seconds
status = client.check_status(response.transaction_id)
print(f"Final status: {status.status}")
except PaymentError as e:
print(f"Error: {e}")
Limitations¶
- No refunds: Semoa does not support API refunds.
- Authentication: Requires multiple credential fields (username, password, client_id, client_secret, api_key) — ensure all are configured correctly.
- Production URL: Verify the production URL with Semoa support (the current default may be sandbox-only).