SDK 221
Les SDK officiels TypeScript, Python et Dart : installation, premier appel, création d'un paiement et vérification d'un webhook.
Les SDK sont générés depuis l'OpenAPI de l'API. Ils vérifient la signature des webhooks et embarquent un instantané des petits jeux de référence (jours fériés, préfixes d'opérateurs, banques, géographie jusqu'à la commune) pour un usage hors ligne.
Pas encore publiés
Les SDK ne sont pas encore publiés : ils seront disponibles sur npm, PyPI et pub.dev à la publication. Les commandes d'installation ci-dessous fonctionneront à ce moment-là. En attendant, l'API s'appelle directement : voir Premier appel.
| Paquet | Langage | Version |
|---|---|---|
@221/sdk | TypeScript | 0.2.0 |
sdk-221 (module sdk221) | Python | 0.2.0 |
sdk221 | Dart et Flutter | 0.2.0 |
Les exemples lisent API_URL (l'URL de base, https://apps.orvlabs.com), API_KEY (la
clé, au format sk_221_pay_test_… ou sk_221_pay_live_…) et WEBHOOK_SECRET dans
l'environnement. Les routes de paiement exigent une clé ; les routes de données
fonctionnent aussi sans clé, avec un quota bas.
Idempotency-Key est propre à chaque paiement : renvoyer la même valeur ne crée
pas de doublon. Un webhook se vérifie sur le corps brut, avant tout décodage
JSON, avec les en-têtes X-221-Timestamp et X-221-Signature ; au-delà de
5 minutes, la signature est refusée. Une livraison peut être rejouée : dédupliquer
sur l'identifiant de l'événement. Le détail des champs est dans
221 Pay.
TypeScript
npm install @221/sdkimport { createApiClient } from '@221/sdk';
const api = createApiClient({ baseUrl: process.env.API_URL, apiKey: process.env.API_KEY });
const { data, error } = await api.POST('/v1/payments', {
params: { header: { 'Idempotency-Key': 'commande-1042' } },
body: {
amount: '5000',
currency: 'XOF',
rail: 'sn_wave',
merchant_reference: 'commande-1042',
return_url: 'https://boutique.example/paiement/retour',
customer_phone: '77 123 45 67',
},
});
if (error) throw new Error(`${error.code}: ${error.message}`);import { verifyWebhook } from '@221/sdk/webhook';
// Express : app.post('/webhooks/221', express.raw({ type: 'application/json' }), (req, res) => …)
const ok = verifyWebhook(process.env.WEBHOOK_SECRET!, req.header('X-221-Timestamp') ?? '', req.body, req.header('X-221-Signature') ?? '');
if (!ok) return res.sendStatus(401);Python
uv add sdk-221 # ou : pip install sdk-221, dans un environnement virtuelimport os
from sdk221 import client
api = client(os.environ["API_KEY"], os.environ["API_URL"])
response = api.get_httpx_client().post(
"/v1/payments",
headers={"Idempotency-Key": "commande-1042"},
json={
"amount": "5000",
"currency": "XOF",
"rail": "sn_wave",
"merchant_reference": "commande-1042",
"return_url": "https://boutique.example/paiement/retour",
"customer_phone": "77 123 45 67",
},
)
response.raise_for_status()
payment = response.json()from sdk221.webhook 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)Dart et Flutter
dart pub add sdk221 # ou : flutter pub add sdk221import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' show MultipartFile;
import 'package:sdk221/sdk221.dart';
Future<void> main() async {
final env = Platform.environment;
final client = createApiClient(apiKey: env['API_KEY'], baseUrl: env['API_URL'] ?? defaultBaseUrl);
final payment = await PaymentsApi(client).paymentsCreate(
MultipartFile.fromString('body', jsonEncode({
'amount': '5000',
'currency': 'XOF',
'rail': 'sn_wave',
'merchant_reference': 'commande-1042',
'return_url': 'https://boutique.example/paiement/retour',
'customer_phone': '77 123 45 67',
})),
idempotencyKey: 'commande-1042',
);
print(payment);
}import 'package:sdk221/sdk221.dart';
final ok = verifyWebhook(webhookSecret, request.headers['x-221-timestamp'] ?? '', rawBody, request.headers['x-221-signature'] ?? '');
if (!ok) return Response(401);Limite : le client généré importe dart:io. Il fonctionne sur la machine
virtuelle Dart, Android, iOS et le bureau, pas sur Flutter web, où la clé ne
doit de toute façon pas se trouver.
Hors ligne
Les jours fériés embarqués couvrent les années présentes dans les données au
moment de la version. holidays(2099) lève une erreur au lieu de renvoyer une
liste vide : pour une autre année, appeler GET /v1/jours-feries?year=.