Skip to main content

Wajub Python SDK

PyPI version Python License: MIT

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-Key on 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() and get_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: global is a Python keyword. Use wajub.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

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

wajub-1.1.1.tar.gz (4.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wajub-1.1.1-py3-none-any.whl (4.8 kB view details)

Uploaded Python 3

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

Hashes for wajub-1.1.1.tar.gz
Algorithm Hash digest
SHA256 6352ae3e4849ca8d5da16c34619240baac70e9ec38ec298307ccb84bfdc92647
MD5 c5a7b26936f7957bd3f29e76ac268014
BLAKE2b-256 58e6866f43002f032575324feb61e951eb6768351aabbd81367a92749993c7dd

See more details on using hashes here.

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

Hashes for wajub-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 97e573539fe8274540d607d78e17eefebf774f39c95fc3f3e6b41e4f729dcc56
MD5 9883832a0c38e73f34f51bde7699389c
BLAKE2b-256 70f5f1687961d4a230d19ed51fa300e39a12e68bd3faf8057a1f6c4910bf8e2a

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.1.1 This release

2 files

1.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page