Journal des changements
Ce qui change dans l’API et les webhooks, daté. Les changements de /v1 restent additifs : une rupture ouvrirait /v2.
Une clé pour chaque sortie d’argent
- POST /v1/refunds et POST /v1/payouts exigent un en-tête Idempotency-Key : rejoué après une coupure, l’appel rend le même remboursement ou le même retrait, sans faire sortir l’argent deux fois. Sans lui, l’appel répond idempotency_key_required (400), avant tout geste.
- Tirez la clé de votre propre référence (rmb-42) : un second clic, une tâche relancée donneront la même.
- Les SDK passent en 0.5.0 : refunds.create et payouts.create demandent leur clé (idempotencyKey en JavaScript, le second argument en PHP) et refusent avant d’appeler.
Les rapports
- GET /v1/reports/summary rend les chiffres d’une période (report_summary) : payé, frais, net, remboursé, paiements réussis et conclus, taux de réussite — les mêmes que la page Rapports de l’espace — et ceux de la période d’avant dans « previous ».
- POST /v1/exports prépare un fichier CSV ou Excel (export, préfixe exp_) : payments, attempts, refunds, payouts, disputes, ledger, invoices ou customers, sur une période, avec les filtres de la page Rapports. Il naît « pending » et répond 202.
- Les webhooks export.ready et export.failed disent quand le fichier est prêt, ou qu’il ne le sera pas. GET /v1/exports/{id}/file le rend ; avant, l’appel répond export_not_ready (409).
- Les en-têtes du fichier sont les noms des colonnes de l’API, ses valeurs les mots de l’API (succeeded, mtn, BEN), ses dates en ISO 8601 avec leur décalage ; les numéros des payeurs y restent masqués.
- Un export plus long que ce que Payiz prépare en un fichier répond export_too_large, avec details.rows et details.max_rows.
- Deux droits de clé, dans le groupe « Rapports » : « Lire les chiffres » et « Préparer des exports ». Un export ne porte que ce que la clé lit déjà : des retraits demandent aussi « Voir les retraits ».
- Les SDK passent en 0.4.0 : reports.summary, exports (create, retrieve, list, file).
Le catalogue, les clients et les factures
- Ce que l’espace sait faire s’ouvre à l’API, par les mêmes règles : /v1/products et leurs prix, /v1/customers, /v1/invoices. Chaque liste se pagine comme les autres, chaque création honore Idempotency-Key.
- Six droits de clé, sous Avancé : « Voir le catalogue » et « Gérer le catalogue », « Voir les clients » et « Gérer les clients », « Voir les factures » et « Créer et envoyer des factures ». Sans eux, l’appel répond insufficient_permissions.
- Un produit (préfixe prd_) a ses prix (prx_) : un par période et par monnaie. Un montant ne se réécrit pas : le prix se retire (POST …/prices/{price_id}/archive), et un autre s’ajoute.
- Un client (cli_) sort avec son numéro masqué. POST /v1/customers/{id}/phone le rend en clair : la lecture s’inscrit au journal d’audit, au nom de la clé, et la réponse ne se garde nulle part — Idempotency-Key n’y fait rien.
- Une facture (fac_) naît en brouillon (« draft »), s’émet (POST …/finalize : son numéro, son lien de paiement, « open »), s’envoie par e-mail (POST …/send, qui émet d’abord un brouillon), et s’annule avec un motif (POST …/cancel), sauf une fois payée. GET /v1/invoices/{id}/pdf rend son PDF.
- Une modification ne change que ce qu’on lui envoie ; null efface.
- Une clé ne porte plus que des droits que l’API vérifie : un autre geste est refusé à sa création, et une clé ancienne perd ceux-là à sa prochaine modification ou à son renouvellement.
- Les SDK passent en 0.3.0 : products (et products.prices), customers, invoices — dont invoices.pdf, qui rend des octets.
Un montant minimum
- Un paiement fait au moins 1 000 F CFA, ou l’équivalent au taux du jour dans une autre monnaie : POST /v1/payments, le prix d’un lien (POST /v1/payment_links) et ses bornes quand il est libre.
- En dessous, l’appel répond amount_below_minimum (400), avec details.min_amount et details.currency. Les SDK connaissent le code.
- GET /v1/payment_methods ne donne plus de min_amount sous ce minimum.
- Un lien créé avant la règle, à un prix plus petit, ne se paie plus : sa page le dit, et le marchand en crée un nouveau.
Le paiement direct
- POST /v1/payments accepte « payer » : la demande part aussitôt sur le téléphone du payeur, sans page de Payiz. Il faut le geste « Paiements · lancer » et un en-tête Idempotency-Key.
- POST /v1/payments/{id}/attempts lance ou relance la demande après un échec ; GET sur le même chemin liste les demandes. Une seule à la fois : sinon attempt_in_progress.
- Chaque paiement porte latest_attempt, un objet payment_attempt (préfixe tnt_) : qui l’a lancée (source), la raison d’un échec (failure_code) et la phrase à montrer au payeur (payer_message).
- GET /v1/payment_methods donne les opérateurs ouverts pour un montant : leur code, leur logo servi par Payiz, leurs bornes et les frais.
- En réel, le direct s’ouvre avec le palier de l’espace ; sinon l’appel répond direct_not_enabled.
- Les SDK passent en 0.2.0 : payments.attempts, paymentMethods, disputes, conversions ; une erreur porte details et requestId ; un appel qui touche un téléphone exige sa clé d’idempotence. En PHP, le code de l’erreur se lit dans $e->errorCode.
Les erreurs et l’idempotence
- Un registre de codes stables, sur la page « Les erreurs » et dans l’OpenAPI : un code ne se retire plus sans passer par ici.
- Chaque erreur porte request_id (aussi dans l’en-tête Request-Id), et details quand le code en a — les opérateurs possibles, les bornes d’un montant.
- Le message suit Accept-Language : français ou anglais.
- Idempotency-Key devient obligatoire quand l’appel touche un téléphone (idempotency_key_required). Passé le point de non-retour, plus jamais de 5xx : l’objet se rend tel qu’il est.
- Trop d’appels d’une clé dans la minute : 429 rate_limited, avec Retry-After.
Webhooks et lectures
- data.object porte l’objet public, le même qu’une lecture de l’API au même instant.
- Trois événements : dispute.created, dispute.closed et conversion.completed. Le catalogue vit dans le contrat, et dans la section webhooks de l’OpenAPI.
- GET /v1/disputes et GET /v1/conversions, en lecture.
- operator vaut un code court et public, propre au pays : mtn, moov, orange.
La fin de la clé publique
- Les clés pk_ n’existent plus. Une page sans serveur ouvre un lien de paiement dans le widget, sans aucune clé : le prix vit dans l’espace.
Le widget et les SDK
- Le widget ouvre la page de paiement dans un voile, sur le site du marchand : <script src="https://pay.payiz.app/payiz.js"></script>, puis Payiz.ouvrir(…).
- Chaque paiement porte un client_secret, rendu à sa création : de quoi laisser une page sans serveur suivre ce paiement-là, et rien d’autre.
- GET /v1/widget/payments/{id}?client_secret=… donne l’état d’un paiement sans clé secrète, en lecture seule et réduit.
- Les SDK Node (npm : payiz) et PHP (composer : payiz/payiz-php) parlent les mêmes noms que l’API, posent l’idempotence d’office et reprennent les pannes passagères.
- Une page de Payiz ne s’encadre plus, sauf celle d’un paiement en mode widget.
Les ressources de /v1
- Les paiements, les remboursements, les liens de paiement, le solde, les bénéficiaires et les retraits s’appellent maintenant par l’API.
- Chaque liste se pagine par curseur : limit (100 au plus) et starting_after, avec data et has_more.
- L’en-tête Idempotency-Key est honoré sur chaque POST : rejouée, la même clé rend la première réponse, avec Idempotent-Replayed: true. Gardée 24 h ; la même clé avec un autre corps répond 409.
- Les dates sortent en secondes depuis 1970, et les montants restent des entiers dans l’unité mineure de la devise.
- GET /v1/refund_reasons donne les motifs de remboursement acceptés : ils se règlent, ne les écrivez pas en dur.
- Un geste fait par une clé apparaît au journal d’audit comme tel, et non au nom de quelqu’un.
Journaux des requêtes
- Chaque appel fait avec une clé s’inscrit dans Développeurs › Journaux, avec son corps, sa réponse et sa durée, gardé 30 jours.
- Les numéros des payeurs et les secrets y sont masqués avant d’être écrits.
Webhooks
- Les destinations se déclarent dans Développeurs › Webhooks, avec les événements voulus et un secret de signature.
- Chaque envoi porte l’en-tête Payiz-Signature (t et v1), sur le corps brut.
- Un échec se retente : 1 min, 5 min, 30 min, 2 h, 6 h, 12 h, puis toutes les 24 h.
- Huit événements : payment.succeeded, payment.attempt_failed, payment.expired, payment.canceled, refund.succeeded, refund.failed, payout.paid, payout.failed.
Clés d’API
- Les clés secrètes et publiques se créent dans Développeurs › Clés API, avec leurs droits et, au besoin, les adresses IP autorisées.
- L’API s’authentifie par « Authorization: Bearer sk_… » ; GET /v1/account dit qui parle.
- Un renouvellement laisse l’ancienne clé valable 24 h ; une révocation la ferme tout de suite.
© 2026 PayizUne question ? L’aide est dans le rond, en bas à droite.