Python
Le package wajub, ses ressources et la version à installer.
Le package wajub est le client Wajub de votre serveur : avec votre clé secrète, il crée des
paiements, lit leur statut et vérifie les signatures des webhooks. Ses appels sont synchrones.
wajub
Stable · GAPyPI
- Version
- 1.2.1
- Runtime
- Python 3.10+, httpx 0.27+
Couvre
- Paiements
- Facturation
- Transferts
- Sync
- Shield
- Taxes
Installer
pip install "wajub>=1.2.1"Créer le client
Le constructeur accepte uniquement des arguments nommés et utilise les variables d'environnement en repli. Dans le cas courant, aucun argument n'est donc nécessaire.
import os
from wajub import Wajub
# Reads WAJUB_API_KEY and WAJUB_WEBHOOK_SECRET from the environment.
wajub = Wajub()
# Or pass them yourself.
wajub = Wajub(
api_key=os.environ["WAJUB_API_KEY"],
webhook_secret=os.environ["WAJUB_WEBHOOK_SECRET"],
)| Argument nommé | Rôle |
|---|---|
api_key | Votre clé sk. ou sk_test.. Utilise WAJUB_API_KEY en repli |
webhook_secret | Le secret whsec_. Utilise WAJUB_WEBHOOK_SECRET en repli |
http_client | Votre propre httpx.Client, pour un proxy ou un transport monté. Donnez-lui base_url="https://api.wajub.com" |
max_network_retries | Nombre de nouvelles tentatives après un échec temporaire |
Un gestionnaire de contexte
Dans un script, une tâche ou un notebook, ouvrez-le dans un bloc with pour qu'il soit fermé à la
fin du bloc. Dans un processus web, créez-le une fois et laissez-le ouvert.
# A script, a task, a notebook: let the block close it.
with Wajub() as wajub:
payment = wajub.payments.create({"amount": 25000, "currency": "XAF"})
# A Django or FastAPI process: build it once at import and leave it open.
wajub = Wajub()Dans du code async, utilisez un thread
Le SDK est synchrone. Dans une vue async def, enveloppez un appel avec asyncio.to_thread ou
exécutez-le dans le pool de threads de votre framework. http_client= accepte un httpx.Client,
pas un httpx.AsyncClient.
Le premier appel
payment = wajub.payments.create(
{
"amount": 25000,
"currency": "XAF",
"email": "amina@example.com",
"description": "Order 4172",
"reference": "order-4172",
"callback": "https://shop.example.com/complete",
}
)
print(payment.id)
print(payment.authorization_url)Les paramètres sont transmis dans un seul dictionnaire, pas comme arguments nommés, et conservent
les noms de champs exacts de l'API. Le résultat est un ApiObject. Il expose chaque champ comme un
attribut tout en se comportant comme un mapping.
payment.authorization_url
payment["authorization_url"]Les montants utilisent l'unité principale
25000 avec XAF représente vingt-cinq mille francs. Une devise décimale accepte un nombre
décimal : "amount": 12.50 avec GHS.
Toutes les ressources du client
| Attribut | Méthodes |
|---|---|
| wajub.global_ | ping, channels, countries, currencies |
| wajub.payments | create, 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.webhooks | construct_event |
globalest un mot-clé de Python : l'accesseur de ping, channels, countries et currencies est doncwajub.global_.- La vérification de signature de
webhookss'exécute en local, sans appel HTTP. Toutes les autres ressources appellent l'API REST. links,invoices,taxetshieldne fonctionnent qu'en live. Une clé sandbox reçoit403 This feature is only available in live mode.sur chacune de leurs méthodes.refundsettransfersne proposent que la création, la lecture et la liste.
Parcourir une liste par pages
list() renvoie un PagedResult. Il contient les lignes, les métadonnées et deux méthodes pour continuer.
page = wajub.payments.list({"status": "succeeded", "per_page": 50})
# page.data holds plain dicts, not ApiObject, so use item access here.
for payment in page.data:
print(payment["id"], payment["amount"])
if page.has_more:
page = page.get_next_page()
# Or let it walk every page for you.
for payment in wajub.payments.list().auto_paging_iter():
reconcile(payment)Idempotence et nouvelles tentatives
Les échecs temporaires sont réessayés pour vous ; max_network_retries en change le nombre. Pour
qu'une création puisse aussi être répétée sans risque de votre côté, fournissez votre propre clé
d'idempotence dès que vous disposez d'un identifiant naturel.
from wajub import RequestOptions
wajub.payments.create(
params,
RequestOptions(idempotency_key=f"order-{order_id}"),
)Pour régler le délai d'expiration des requêtes, fournissez votre propre client :
import httpx
wajub = Wajub(http_client=httpx.Client(base_url="https://api.wajub.com", timeout=60.0))Agir pour un compte connecté
from wajub import RequestOptions
wajub.payments.create(
{"amount": 25000, "currency": "XAF", "email": buyer.email},
RequestOptions(sync=seller.wajub_account_id),
)La configuration est présentée dans Sync.
Webhooks
construct_event vérifie la signature et renvoie l'événement analysé. Il a besoin du corps
exactement tel qu'il est arrivé.
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from .wajub_client import wajub
@csrf_exempt
def wajub_webhook(request):
try:
event = wajub.webhooks.construct_event(
request.body,
request.headers["X-Wajub-Signature"],
request.headers["X-Wajub-Timestamp"],
)
except Exception:
return HttpResponse(status=400)
if event["event"] == "payment.succeeded":
fulfil(event["data"])
return HttpResponse(status=200)request.json n'est pas le corps
La signature est calculée sur le corps brut, et un dictionnaire analysé puis resérialisé ne lui
correspond plus. Utilisez request.body
dans Django, get_data() dans Flask ou await request.body() dans FastAPI. Toutes ces méthodes
renvoient des octets, comme l'exige construct_event.
Si vos horloges dérivent, construct_event accepte la tolérance en secondes comme quatrième
argument. Consultez
Vérification de signature.
Erreurs
from wajub import InvalidRequestError, RateLimitError, WajubError
try:
wajub.payments.create(params)
except InvalidRequestError as error:
# error.errors vaut {"amount": "The amount must be at least 25."}, une chaîne par champ
return JsonResponse({"fields": error.errors}, status=422)
except RateLimitError as error:
return HttpResponse(status=503, headers={"Retry-After": str(error.retry_after or 5)})
except WajubError as error:
logger.error("wajub failed", extra={"code": error.code, "status": error.http_status})
raise| Classe | Cas de déclenchement |
|---|---|
AuthenticationError | 401 |
PermissionError | 403 |
NotFoundError | 404 |
InvalidRequestError | 400 et 422 |
RateLimitError | 429, avec retry_after en secondes |
WajubError | Tout autre statut. C'est aussi la classe de base de toutes les erreurs ci-dessus |
ApiConnectionError | Aucune réponse, à cause du réseau ou d'un délai d'expiration |
WebhookSignatureVerificationError | Un webhook dont la signature n'a pas été vérifiée |
Toutes contiennent message, code, http_status, errors et raw.
PermissionError masque un type intégré
wajub.PermissionError et le PermissionError natif de Python portent le même nom. Un simple
from wajub import * remplace silencieusement le type intégré. Importez les noms que vous utilisez,
ou conservez le module : import wajub puis except wajub.PermissionError.
Typage
mypy et Pyright lisent les annotations du package sans installation supplémentaire. Les paramètres
sont des dict[str, Any] et les résultats des ApiObject : typez vous-même les champs dont vous
dépendez.
from typing import TypedDict
class Checkout(TypedDict):
session_token: str
pay_url: str
def start_checkout(order_id: str, amount: float, email: str) -> Checkout:
payment = wajub.payments.create(
{
"amount": amount,
"currency": "XAF",
"email": email,
"reference": order_id,
},
RequestOptions(idempotency_key=f"order-{order_id}"),
)
return {
"session_token": payment.authorization_token,
"pay_url": payment.authorization_url,
}Débiter sans page hébergée
payment = wajub.payments.create(
{"amount": 25000, "currency": "XAF", "phone": "+237670000000"}
)
wajub.payments.process(
payment.id,
{"channel": "cm.mtn", "phone": "+237670000000"},
)Un canal suit le format country.operator. Ainsi, cm.mtn désigne MTN Mobile Money au Cameroun.
La liste complète se trouve dans Mobile Money. Le payeur
doit toujours approuver l'opération sur son téléphone. Le résultat arrive donc par webhook.
Effectuer un payout
transfer = wajub.transfers.create(
{
"amount": 100000,
"currency": "XAF",
"beneficiary": {
"name": "Amina Diallo",
"channel": "cm.mtn",
"phone": "+237670000000",
},
"reference": "payout-892",
},
RequestOptions(idempotency_key="payout-892"),
)beneficiary accepte aussi l'identifiant ben_… d'un bénéficiaire enregistré. Cette forme est
préférable dès que vous payez plusieurs fois la même personne.
Développement local
Transférez les webhooks vers votre machine avec la CLI au lieu d'exposer un tunnel.
wajub listen --forward-to localhost:8000/webhooks/wajub
wajub trigger payment.succeededPour en savoir plus, consultez la CLI.
Pages associées
- Démarrage rapide des SDKsLe même premier appel dans cinq langages, présentés côte à côte.
- WebhooksTous les événements et leurs garanties de livraison.
- Conventions de nommage des SDKsLes noms qui suivent Python, et ceux qui gardent l'orthographe de l'API.
- IdempotenceCe que protège une clé et pendant combien de temps.
- Gestion des erreursLes échecs à retenter et ceux à présenter à l'utilisateur.
- Vue d'ensemble de la référence APILes endpoints utilisés par chaque méthode ci-dessus.