Skip to content

Cash-in déprécié ​

Routes historiques du cash-in public. Elles restent servies pour les partenaires déjà en production. Toute nouvelle intégration utilise POST /checkout/sessions avec une clé sk_ : Référence API.

Chaque réponse porte :

http
Deprecation: true
Sunset: Thu, 30 Sep 2027 00:00:00 GMT
Link: </api/v1/checkout/sessions>; rel="successor-version"

Les mêmes chemins existent sous /api et sous /api/v1. Les deux préfixes ont le même contrat. Les réponses réussies sont en 200, y compris les POST. Le corps est en camelCase. Il n'y a pas d'enveloppe { items }.

Base :

http
https://paymentdev-api.akieni.tech/api
https://paymentdev-api.akieni.tech/api/v1

Authentification ​

POST /generate-application-access-token

Corps :

ChampTypeObligatoire
apiKeystring, 1-500Oui
secretKeystring, 1-500Oui

Réponse 200 :

ChampTypeDescription
tokenstringJeton oat_…, à envoyer en Authorization: Bearer
expiresAtstring ISO 8601Expiration, 2 heures après l'émission

Clé inconnue, secret incorrect, jeton expiré, révoqué ou application inactive : 401.

json
{ "message": "Unauthorized access", "status": 401, "code": "E_UNAUTHORIZED_ACCESS" }

POST /revoke-application-access-token révoque uniquement le jeton présenté. Corps vide. Réponse 200 :

json
{ "message": "Your app session have been removed!" }

Le couple apiKey / secretKey est délivré pour une application. Il ne remplace pas une clé sk_.

Montant ​

amount est un entier strictement positif, au plus 2147483647. Un nombre à virgule (10.5) est refusé. Pour le franc CFA, l'entier est le montant en francs : 1600 vaut 1 600 XAF.

Ce montant est le dû demandé. Il n'inclut pas les frais de service. Les frais apparaissent seulement dans totalAmount du contrôle de statut, une fois un encaissement engagé.

Ouvrir un checkout ​

POST /init-checkout

Jeton oat_ requis.

ChampTypeObligatoireDescription
externalNumberstring, 1-200OuiIdentifiant dossier côté partenaire
amountentierOuiDû demandé
descriptionstring, max 2000NonLibellé, repris dans le webhook (note)
typeecommerce ou serviceNonType de paiement
itemstableau, 1 à 50OuiLignes. number unique dans le tableau
customerobjetNonSi présent : full_name, address, phone requis
merchantobjetNonURLs de retour et webhook

Ligne items : number (1-64), name (1-200), price (nombre ≥ 0), quantity (nombre ≥ 0).

merchant :

ChampDescription
redirectUrlRetour après succès. Origine autorisée pour l'application.
backUrlRetour après abandon. Même règle d'origine.
webhookUrlURL publique https du partenaire. En production, http est refusé.
coverUrlVisuel, non utilisé pour l'appel sortant.
noteNote, max 2000 caractères.

Une URL de webhook avec identifiants (user:pass@hôte), un hôte local ou une adresse privée est refusée avant toute création de paiement.

Réponse 200, clés exactes :

ChampDescription
paymentIdIdentifiant entier du paiement
externalNumberEcho du dossier
tokenJeton de formulaire du checkout. Ce n'est pas un oat_.
redirectUrlPage de checkout hébergée

Tant que le paiement est encore created (aucun encaissement engagé), un nouvel init-checkout avec le même externalNumber met à jour la même ligne, y compris le montant, et conserve la même redirectUrl.

Si le paiement est déjà pending, completed ou failed, le même externalNumber ouvre un nouveau paiement et un nouveau débit.

Le paiement par carte compatible avec une page hébergée passe par init-checkout, pas par partners/payments.

Débit partenaire ​

POST /partners/payments

ChampTypeObligatoireDescription
externalNumberstring, 1-200OuiIdentifiant dossier
amountentierOuiDû demandé
descriptionstring, max 2000NonLibellé
providerstring, 1-32Ouimtn, airtel, visa, mastercard
customerobjetConditionnelphone obligatoire pour mtn et airtel
itemstableau, 1 à 50OuiMêmes règles que init-checkout

Téléphone : format international +242…, ou numéro local 0 suivi de 8 à 14 chiffres, converti avec l'indicatif +242. Exemple : 056479451 devient +24256479451. Numéro invalide : 422.

json
{ "message": "Invalid phone number", "status": 422, "code": "INVALID_PHONE_NUMBER" }

Réponse 200, clés exactes : paymentId, number, externalNumber, status, amount, provider.

number suit T + année sur 2 chiffres + mois sur 2 chiffres + 6 chiffres (T2609000001). status vaut pending. amount est le dû demandé, pas le total frais inclus. Cette réponse ne contient pas de redirectUrl.

bgfi et tout autre fournisseur : 404.

json
{ "message": "Payment provider not found", "status": 404, "code": "PROVIDER_NOT_FOUND" }

Fournisseur reconnu mais non activé pour l'application : 403 PROVIDER_NOT_CONFIGURED.

Si l'opérateur de paiement échoue avant qu'un encaissement existe : 502 GATEWAY_REQUEST_FAILED. Si un encaissement est déjà pending ou accepté, la réponse reste 200 avec status: pending.

Contrôle de statut ​

GET /transactions/{number}/check-status

number est le numéro T… du paiement, pour l'application authentifiée. Inconnu : 404.

json
{ "message": "Row not found", "status": 404, "code": "E_ROW_NOT_FOUND" }

Plusieurs paiements partagent parfois le même externalNumber. Le contrôle par numéro vise une ligne. Il n'y a pas de recherche par externalNumber.

ChampDescription
idpaymentId
numberNuméro T…
externalNumberDossier partenaire
statuscreated, pending, completed, failed, cancelled
paidAmountDû demandé
totalAmountDû demandé tant qu'aucun encaissement n'est engagé, puis dû + frais
paidAtDate ISO si completed, sinon null
description, typeEcho de la création
customerEcho, ou null
transactionItemsEcho des lignes
paymentGateway{ id, name, description, logo } ou null si aucun fournisseur
financialTransactionIdRéférence opérateur, ou null

paymentIntentId, extraInfo, paymentInfo et paymentFailedReason valent null.

Situationstatus
Checkout ouvert, aucun encaissementcreated
Encaissement en cours ou déjà acceptépending
Seul un encaissement en échec, checkout ouvertfailed
Paiement terminécompleted
Checkout annulécancelled
Checkout expiréfailed

Passerelles ​

GET /partners/payment-gateways

Réponse 200 : un tableau, éventuellement vide. Pas d'objet enveloppe.

idnameTéléphone requis
1mtnOui
2airtelOui
3visaNon
4mastercardNon

Une passerelle n'apparaît que si le canal correspondant est activé. commissionPercentage est un ratio (0.015 pour 1,5 %). commissionValue est un montant fixe dans la même unité que amount. logo vaut null.

Webhook partenaire ​

Après un paiement completed, ou lorsque le statut notifié est failed, Epayment envoie POST JSON à l'URL de webhook courante de l'application. L'URL enregistrée sur le paiement sert de repli.

En-tête envoyé : Content-Type: application/json seulement. Pas de signature, pas de Authorization.

ChampDescription
paymentIdIdentifiant entier
externalNumberDossier partenaire, sans suffixe interne
amountDû demandé (paidAmount)
statuscompleted ou failed
paidAtDate ISO si completed, sinon null
notedescription, ou null

Un checkout cancelled ou expired part en webhook avec status: failed. Le contrôle de statut, lui, distingue encore cancelled.

Les statuts created et pending ne déclenchent pas d'appel. Un même statut terminal n'est renvoyé qu'après une réponse 2xx. Un échec d'appel ne change pas l'état du paiement.

Erreurs ​

Validation (422), sans code d'enveloppe ministry :

json
{
  "message": "Validation failed",
  "errors": [{ "message": "Expected integer", "rule": "type", "field": "amount" }]
}

rule vaut type, range, enum, distinct, url ou required. Les autres erreurs ont exactement message, status et code.

CodeHTTPSituation
E_UNAUTHORIZED_ACCESS401Clé, secret ou jeton refusé
E_ROW_NOT_FOUND404Numéro inconnu pour cette application
PROVIDER_NOT_FOUND404provider hors mtn, airtel, visa, mastercard
PROVIDER_NOT_CONFIGURED403Fournisseur non activé
INVALID_PHONE_NUMBER422Téléphone inutilisable
GATEWAY_REQUEST_FAILED502Échec opérateur avant tout encaissement
E_TOO_MANY_REQUESTS429Quota dépassé
E_INTERNAL_ERROR500Erreur interne

Quotas, par identifiant d'accès et par chemin, sur une minute : 5 requêtes pour le jeton, la révocation, init-checkout et partners/payments ; 30 requêtes pour le contrôle de statut et la liste des passerelles.

Correspondance ​

Cash-in dépréciéCheckout ministry
apiKey + secretKey, puis oat_Authorization: Bearer sk_…
externalNumberorder_id
amount entieramount en unité mineure (XAF : même entier)
redirectUrl de init-checkoutcheckout_url
GET /transactions/{number}/check-statusGET /checkout/sessions?order_id=
Webhook non signé completed / failedWebhook signé checkout.completed et statuts terminaux

Plateforme d'orchestration de paiement DPI. Les fonds ne transitent pas par Epayment.