SDK Python 221
Client de l'API 221 généré depuis l'OpenAPI par
openapi-python-client
(EF-221-02), vérification des signatures de webhook et données de référence hors
ligne (EF-221-03). Distribution sdk-221, module sdk221. Site et documentation :
https://221.orvlabs.com/documentation. Le code généré est rebâti dans le dépôt
principal (generate.sh) ; ce dépôt publie le résultat.
| Module | Contenu | Origine |
|---|---|---|
sdk221.generated |
Client, AuthenticatedClient, api.<tag>.<opération>, models |
Généré (httpx + attrs), jamais modifié à la main |
sdk221 |
client(api_key, base_url), verify_webhook(...) |
Écrit à la main |
sdk221.offline |
holidays, holiday, operator_for, banks, bank, places, place, snapshot |
Instantané versionné de server/data.json |
Installation
uv add sdk-221 # ou, dans un environnement virtuel : pip install sdk-221
Pas encore publié sur PyPI : la commande fonctionnera à la publication.
Développement
cd packages/sdk-python
./generate.sh # Node et uv ; contrat Go (make openapi, sans serveur) : OpenAPI, instantané, client
uv run pytest # tests/test_api.py appelle l'API Go locale (make dev)
Clés API
Une clé a la forme sk_221_pay_test_… (mode test) ou sk_221_pay_live_… (mode réel).
Les clés déjà émises avec 221pay_test_, 221pay_live_ ou sk_221_ restent acceptées.
import os
from sdk221 import client
api = client(os.environ["API_KEY"]) # Authorization: Bearer <clé> ; base_url= pour une autre adresse
Les routes de données fonctionnent aussi sans clé (client()), avec un quota bas
par adresse IP.
Créer un paiement
Idempotency-Key est propre à chaque paiement : renvoyer la même valeur ne crée
pas de doublon. Le contrat décrit le corps des routes de paiement comme du
binaire et ne liste que la réponse 200, alors que la création répond 201 : on
passe par le client httpx du SDK, qui porte déjà la clé.
response = api.get_httpx_client().post(
"/v1/payments",
headers={"Idempotency-Key": "commande-1042"},
json={
"amount": "10000",
"currency": "XOF",
"rail": "sn_wave",
"merchant_reference": "commande-1042",
"return_url": "https://boutique.example/merci",
},
)
response.raise_for_status()
payment = response.json()
Vérifier un webhook
Lisez le corps brut avant tout décodage JSON ; refusez la requête si la
fonction renvoie False (signature fausse, ou horodatage de plus de 5 minutes,
max_age_seconds pour changer la durée).
from sdk221 import verify_webhook
# FastAPI : raw_body = await request.body()
if not verify_webhook(WEBHOOK_SECRET, request.headers.get("X-221-Timestamp", ""), raw_body, request.headers.get("X-221-Signature", "")):
raise HTTPException(status_code=401)
Dédupliquez sur l'identifiant de l'événement : une livraison peut être rejouée.
Premier appel, sans clé
from sdk221 import client
from sdk221.generated.api.jours_feries import list_jours_feries
api = client() # https://apps.orvlabs.com par défaut
jours = list_jours_feries.sync(client=api, year="2026")
print(jours.data[0]["name"]["fr"]) # « Jour de l'an »
Chaque opération existe en sync, sync_detailed, asyncio et asyncio_detailed.
Erreurs et quotas
sync_detailed renvoie le statut, les en-têtes et parsed : le modèle attendu
pour 200, un Error (code, message, request_id, fields) pour les
erreurs décrites, None sinon. Testez code (en majuscules, par exemple
QUOTA_EXCEEDED), pas le statut.
from sdk221.generated.models import Error
response = list_jours_feries.sync_detailed(client=api, year="2026")
if response.status_code == 429:
wait = int(response.headers["Retry-After"]) # secondes ; ou utilisez une clé
elif isinstance(response.parsed, Error):
raise RuntimeError(f"{response.parsed.code}: {response.parsed.message}")
Ne relancez pas un 429 en boucle : attendez Retry-After secondes.
Hors ligne
from sdk221 import offline
offline.holidays(2026) # jours fériés (date_status : confirmee ou previsionnelle) ; ValueError hors des années embarquées
offline.operator_for("771234567") # opérateur du préfixe d'origine (portabilité possible)
offline.bank("K 0010 A") # par id ou code banque BCEAO
offline.places(level="region", q="thies")
offline.place("reg_om6lpn2l") # avec ancêtres et enfants, comme l'API
offline.snapshot["built_at"] # date des données embarquées
Les fonctions renvoient les mêmes objets JSON que l'API. Validation et
formatage des numéros et des montants (modules telephonie et monnaie) : dans
le SDK TypeScript seulement pour l'instant.
Exemple
uv run python examples/premier_appel.py # API_KEY et API_URL facultatifs
normalize() dans offline.py recopie celle de server/internal/api/data.go ;
tests/test_api.py compare les recherches hors ligne aux réponses de l'API (le
quota anonyme est de 10 appels par minute).
Metadata
Release files for sdk-221 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sdk_221-0.2.1.tar.gz | 163.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sdk_221-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 584.8 kB
Release files / sdk_221-0.2.1.tar.gz
| Download URL | sdk_221-0.2.1.tar.gz |
|---|---|
| Size | 163.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
15931d90741368428325a17e84e2ded08e72e90ba70d585ce48cca8f88d9a3ed
|
|
BLAKE2b-256 checksum How to use checksums |
60de6613f2dfa84e8614aef897440f4a73e46fe31ce6604ca13aee44d6568f20
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.5 {"installer":{"name":"uv","version":"0.11.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / sdk_221-0.2.1-py3-none-any.whl
| Download URL | sdk_221-0.2.1-py3-none-any.whl |
|---|---|
| Size | 421.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5165890c56588e9954145218bcd40419beb5d88238a54e5713277ddd2e3fa3ed
|
|
BLAKE2b-256 checksum How to use checksums |
9c73f40ef986d0644fe9e46976165e7afe515663f7a3be8d279177dc2c3d770c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.5 {"installer":{"name":"uv","version":"0.11.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|