Wajub Python SDK
Official server-side SDK for the Wajub merchant API. Accept mobile-money and card payments across Africa with a Stripe-inspired, resource-oriented client.
Use Wajub.js for embedded checkout in the browser. Use this SDK on your backend with a secret (sk_) or restricted (rk_) API key — never expose secret keys in client-side code.
Features
- Resource-oriented API (
wajub.payments,wajub.customers, …) - Automatic
Idempotency-Keyon mutating requests (override per call) - Typed errors per HTTP status (
AuthenticationError,RateLimitError, …) - Automatic retries on 429 and 5xx (max 2, exponential backoff)
- Page-based pagination with
auto_paging_iter()andget_next_page() - Webhook signature verification (HMAC-SHA256, timestamp tolerance)
Requirements
| Requirement | Version |
|---|---|
| Python | 3.10 or later |
| HTTP client | httpx 0.27+ (installed automatically) |
Installation
pip install wajub
Quick start
Amounts are passed in the smallest currency unit (e.g. cents for EUR/USD; whole francs for XAF).
Redirect checkout
import os
from wajub import Wajub
wajub = Wajub(api_key=os.environ["WAJUB_API_KEY"])
payment = wajub.payments.create({
"amount": 15000,
"currency": "XAF",
"email": "buyer@example.com",
"callback": "https://shop.example.com/order/complete",
})
print(payment.authorization_url)
Inline / overlay (embed token)
embed = wajub.payments.create({
"amount": 15000,
"currency": "XAF",
"metadata": {"mode": "embed"},
})
# Pass to Wajub.js: embed.authorization_token
create() and retrieve() return a typed Payment object — prefer attribute access (payment.authorization_url). List pages from list() yield plain dicts.
Django / Flask
import os
from wajub import Wajub
wajub = Wajub(
api_key=os.environ["WAJUB_API_KEY"],
webhook_secret=os.environ.get("WAJUB_WEBHOOK_SECRET"),
)
Webhook view (Django)
Use the raw request body:
from django.http import HttpResponse, HttpResponseBadRequest
from django.views.decorators.csrf import csrf_exempt
from wajub import Wajub
from wajub import WebhookSignatureVerificationError
wajub = Wajub(api_key=os.environ["WAJUB_API_KEY"], webhook_secret=os.environ["WAJUB_WEBHOOK_SECRET"])
@csrf_exempt
def wajub_webhook(request):
try:
event = wajub.webhooks.construct_event(
request.body, # bytes — not request.POST or parsed JSON
request.headers.get("X-Wajub-Signature", ""),
request.headers.get("X-Wajub-Timestamp", ""),
)
except WebhookSignatureVerificationError:
return HttpResponseBadRequest()
if event.get("type") == "payment.succeeded":
pass # fulfill order
return HttpResponse(status=200)
Note:
globalis a Python keyword. Usewajub.global_to access global resources.
Configuration
| Variable | Description |
|---|---|
WAJUB_API_KEY |
Secret or restricted API key (sk_, sk_test., rk_, …) |
WAJUB_WEBHOOK_SECRET |
Webhook signing secret (whsec_) for construct_event() |
Test mode is selected by your API key prefix (sk_test.…), not by the API URL. Production calls always go to https://api.wajub.com.
Resources (merchant API)
| Attribute | Methods |
|---|---|
wajub.global_ |
ping, channels, countries, currencies |
wajub.payments |
create, initialize, retrieve, list, cancel, process, process_split, list_refunds |
wajub.customers |
create, retrieve, update, delete, list, block, unblock, activate, deactivate, list_tax_ids, create_tax_id, delete_tax_id |
wajub.refunds |
create, retrieve, list |
wajub.transfers |
create, retrieve, list |
wajub.beneficiaries |
create, retrieve, update, delete, list |
wajub.links |
create, retrieve, update, delete, list |
wajub.invoices |
create, retrieve, update, delete, list, send, mark_paid, cancel |
wajub.accounts |
create, retrieve, update, delete, list, regenerate_token |
wajub.webhook_endpoints |
create, retrieve, update, delete, list, rotate_secret |
wajub.balance |
retrieve |
wajub.events |
list, retrieve, resend |
wajub.disputes |
list, retrieve, submit_evidence, accept, close, send_message |
wajub.identity |
resolve, validate |
wajub.tax |
get_settings, update_settings, rates, calculate, reports, list_codes, retrieve_code, list_registrations, create_registration, retrieve_registration, update_registration, delete_registration, jurisdictions, thresholds, threshold_alerts |
wajub.shield |
get_settings, update_settings, stats, list_blocklist, add_to_blocklist, remove_from_blocklist |
wajub.listen |
config, auth |
wajub.webhooks |
construct_event (local — no HTTP) |
Sync (Connect)
from wajub import RequestOptions
wajub.payments.create(params, RequestOptions(sync="acct_sync_ref"))
Webhooks
from wajub import WebhookSignatureVerificationError
try:
event = wajub.webhooks.construct_event(
raw_body, # bytes — must be raw body, not parsed JSON
request.headers["X-Wajub-Signature"],
request.headers["X-Wajub-Timestamp"],
)
except WebhookSignatureVerificationError:
return 400
if event.get("type") == "payment.succeeded":
pass # fulfill order
During local development, use the Wajub CLI to forward webhooks to your machine.
Pagination
page = wajub.payments.list({"per_page": 50})
for payment in page.auto_paging_iter():
print(payment["id"], payment["status"])
# Manual page control
first = wajub.payments.list()
if first.has_more:
second = first.get_next_page()
Idempotency
POST and PUT requests automatically receive an Idempotency-Key header. Pass your own:
from wajub import RequestOptions
wajub.payments.create(params, RequestOptions(idempotency_key=f"order-{order_id}"))
Error handling
from wajub import AuthenticationError, InvalidRequestError, RateLimitError
try:
wajub.payments.create(params)
except InvalidRequestError as e:
print(e.errors) # field-level validation errors
except AuthenticationError:
pass # 401 — bad API key
except RateLimitError:
pass # 429 — back off and retry
Development
pip install -e ".[dev]"
pytest
Documentation & support
- Full API reference: docs.wajub.com/libraries/sdks/python
- Report issues: github.com/wajubhq/wajub-python/issues
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wajub-1.1.1.tar.gz.
File metadata
- Download URL: wajub-1.1.1.tar.gz
- Upload date:
- Size: 4.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6352ae3e4849ca8d5da16c34619240baac70e9ec38ec298307ccb84bfdc92647
|
|
| MD5 |
c5a7b26936f7957bd3f29e76ac268014
|
|
| BLAKE2b-256 |
58e6866f43002f032575324feb61e951eb6768351aabbd81367a92749993c7dd
|
File details
Details for the file wajub-1.1.1-py3-none-any.whl.
File metadata
- Download URL: wajub-1.1.1-py3-none-any.whl
- Upload date:
- Size: 4.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97e573539fe8274540d607d78e17eefebf774f39c95fc3f3e6b41e4f729dcc56
|
|
| MD5 |
9883832a0c38e73f34f51bde7699389c
|
|
| BLAKE2b-256 |
70f5f1687961d4a230d19ed51fa300e39a12e68bd3faf8057a1f6c4910bf8e2a
|