Jour 1 — Lundi 9h. « On a besoin d'Orange Money pour vendredi. » Notre CEO, à moitié rigolant. On a 4,5 jours.

Obtenir l'accès

Pas de sandbox publique. Il faut un contrat commercial, KYC (RC, ICE, attestation fiscale). On avait préparé 3 semaines à l'avance. À 14h on reçoit : CLIENT_ID, SECRET_KEY, endpoint. Doc : PDF de 38 pages.

Points clés : - OAuth 2.0 client_credentials. Token valable 1h. - Initier paiement : POST avec montant en centimes, numéro, référence marchand unique. - Webhook : signature HMAC-SHA256 dans header X-Orange-Signature. - Idempotence critique. Le webhook peut être rappelé plusieurs fois.

Jour 2 : première intégration

FastAPI, httpx async. 401 : token en Bearer, pas Basic. 422 : numéro sans espace ni tiret. Puis succès.

Jour 2 après-midi : webhook

HMAC du body JSON — mais sans espaces, clés dans l'ordre, bytes bruts. Testé trois variantes.

import hmac, hashlib def verify(body_bytes: bytes, sig: str, secret: str) -> bool: expected = hmac.new(secret.encode(), body_bytes, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, sig)

Utilisez compare_digest, pas ==. Protection timing attack.

Jour 3 : idempotence

Contrainte UNIQUE sur idempotency_key. INSERT échoue silencieusement la seconde fois. Toujours 200 OK — sinon Orange retente.

Jour 3 soir : edge cases

Paiement en attente depuis 25 minutes. Cron job qui poll toutes les 5 min les paiements >10 min.

Jour 4 : les CIN

Orange Money demande 4 derniers chiffres CIN pour montants >5000 dh. Ajouté un écran intermédiaire.

Jour 5 : démo

4 salons. 3 signent le jour même. Le 4e veut Maroc Telecom — promis pour 2 semaines plus tard.

Ce qu'on a appris

1. La doc n'est jamais complète. 30% du temps à deviner. 2. Testez avec de vrais comptes. 3. Idempotence architecturale, non optionnelle. 4. compare_digest partout. 5. Polling de secours obligatoire.

— Y. El Ghazi.