TTekSafi Pay / API
api.teksafipay.com · v1
Documentation · API ApplicationsDocumentation · API Applications

Intégrer les paiements TekSafi PayIntegrating TekSafi Pay payments

Ce guide s'adresse aux équipes techniques des marchands qui intègrent l'encaissement mobile money via l'API TekSafi Pay. Tous les exemples ci-dessous utilisent des données réelles d'un marché actif (Congo-Brazzaville, XAF, MTN Mobile Money).

This guide is for merchant engineering teams integrating mobile money collection via the TekSafi Pay API. Every example below uses real data from a live market (Congo-Brazzaville, XAF, MTN Mobile Money).

Démarrage rapideQuickstart

1

Créez votre compte gratuitement (particulier ou marchand) sur teksafipay.com/inscription. Votre application démarre automatiquement en mode Sandbox, sans engagement. (Un compte peut aussi être créé directement par un administrateur TekSafi via le back-office : il démarre alors pré-vérifié, directement en mode Live.)

Create your account for free (individual or merchant) at teksafipay.com/inscription. Your application automatically starts in Sandbox mode, with no commitment. (An account can also be created directly by a TekSafi administrator through the back-office : it then starts pre-verified, directly in Live mode.)

2

Connectez-vous une première fois pour générer votre clé API et votre clé de collecte (voir Authentification).

Sign in once to generate your API key and your collection key (see Authentication).

3

Échangez votre clé API contre un jeton de session, puis appelez POST /transactions/collection pour votre premier encaissement simulé (voir Collecter un paiement).

Exchange your API key for a session token, then call POST /transactions/collection for your first simulated collection (see Collecting a payment).

4

Une fois vos tests concluants, soumettez vos documents KYC depuis le portail marchand. Après validation par un admin, votre compte bascule en mode Live — mêmes appels, mêmes réponses, mais argent réel.

Once your tests pass, submit your KYC documents from the merchant portal. After admin approval, your account switches to Live mode — same calls, same responses, but real money.

Premier appel — obtenir un jetonFirst call — getting a token
curl -X POST https://api.teksafipay.com/api/v1/auth \
  -H "x-application-id: 8796c6c4-aa02-403f-bd95-3f7254dda8e9" \
  -H "x-api-key: a47f9e21-6c3d-4b8a-9f12-7e4d8c2b91a5"

Sandbox vs LiveSandbox vs Live

Le mode est un attribut de votre compte, pas un paramètre de requête : il n'y a ni en-tête ni flag "test mode" à passer. Tant que votre compte est en Sandbox, chaque appel — collection, décaissement, webhook — passe par un simulateur interne au lieu de l'agrégateur réel ; le contrat de requête/réponse est identique dans les deux modes, seul le traitement change.

Mode is an attribute of your account, not a request parameter : there's no "test mode" header or flag to pass. As long as your account is in Sandbox, every call — collection, disbursement, webhook — runs through an internal simulator instead of the real aggregator; the request/response contract is identical in both modes, only the processing changes.

i

En Sandbox, un compte LIVE ne voit jamais l'historique Sandbox d'un autre compte, et inversement : les transactions sont toujours filtrées par le mode courant de votre application.

In Sandbox, a LIVE account never sees another account's Sandbox history, and vice versa : transactions are always filtered by your application's current mode.

AuthentificationAuthentication

Toutes les routes de paiement exigent un jeton (JWT) dans l'en-tête Authorization : Bearer <jeton>. Un jeton expire après 1 heure — prévoyez de le renouveler.

Every payment route requires a token (JWT) in the Authorization : Bearer <token> header. A token expires after 1 hour — plan to refresh it.

Obtenir un jetonGetting a token

MéthodeMethodUsageUse case
POST/auth avec en-têteswith headers x-application-id / x-api-keyÉchange direct clé → jeton. Recommandé pour un serveur backend.Direct key → token exchange. Recommended for a backend server.
POST/auth/login-key avecwith { applicationId, key }Équivalent en JSON plutôt qu'en en-têtes.Same thing, as JSON instead of headers.
RequêteRequest
POST /auth/login-key

{
  "applicationId": "8796c6c4-aa02-403f-bd95-3f7254dda8e9",
  "key": "a47f9e21-6c3d-4b8a-9f12-7e4d8c2b91a5"
}
RéponseResponse · 200
{
  "success": true,
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_in": 3600,
  "token_type": "Bearer"
}

Générer vos clésGenerating your keys

Vos clés démarrent à null à la création du compte — générez-les vous-même une fois connecté (nécessite un jeton obtenu via le dashboard, authMethod email).

Your keys start at null when the account is created — generate them yourself once signed in (requires a token obtained via the dashboard, authMethod email).

POST/applications/generate-key?keyType=API_KEY
Compte authentifiéAuthenticated account
Paramètres de requêteQuery parameters
ChampFieldTypeRequisRequiredDescriptionDescription
keyTypeenumouiyesAPI_KEY · COLLECTION_KEY · DISBURSEMENT_KEY
forcebooleannonnoRégénère même si une clé existe déjà (l'ancienne devient invalide)Regenerates even if a key already exists (the old one becomes invalid)
RéponseResponse · 200
{
  "success": true,
  "message": "Clé générée avec succès.",
  "data": {
    "oldKey": null,
    "newKey": "a47f9e21-6c3d-4b8a-9f12-7e4d8c2b91a5"
  }
}
i

La nouvelle clé est aussi envoyée par email. COLLECTION_KEY et DISBURSEMENT_KEY ne peuvent être générées que si votre compte a respectivement collectionAllowed/disbursementAllowed activé par un admin.

The new key is also emailed to you. COLLECTION_KEY and DISBURSEMENT_KEY can only be generated if your account has collectionAllowed/disbursementAllowed enabled by an admin, respectively.

Trois types de clé, trois usagesThree key types, three purposes

CléKeySert àUsed for
apiKeyS'authentifier et obtenir un jeton (Authenticating and obtaining a token (Authorization: Bearer)
collectionKeyRequise en plus du jeton, en en-tête Required alongside the token, as header X-Collection-Key, pourfor POST /transactions/collection
disbursementKeyMême principe pour les décaissements (Same idea for disbursements (X-Disbursement-Key)

Découvrir vos marchés & moyens de paiementDiscovering your markets & payment methods

GET/applications/markets-payment-methods
Compte authentifiéAuthenticated account

Toujours interroger cette route plutôt que de coder en dur un format de numéro ou un taux : c'est la source de vérité, propre à votre compte, et elle reflète les changements faits par un admin en temps réel.

Always query this route instead of hardcoding a number format or a rate : it's the source of truth for your account, and it reflects changes an admin makes in real time.

RéponseResponse · 200
{
  "success": true,
  "data": {
    "appName": "Boutique Malonga",
    "markets": [
      {
        "marketId": "f394448f-65e2-46b4-b213-a1159e74ba58",
        "marketActive": true,
        "country": { "code": "CG", "name": "République du Congo", "callingCode": "+242", "currency": "XAF" },
        "paymentMethods": [
          {
            "code": "MTN_MOMO_COG",
            "name": "MTN Mobile Money",
            "type": "MOBILE_MONEY",
            "regexValidation": "^24206\\d{7}$",
            "validationFormat": "242 06XXXXXXX",
            "rates": { "collection": 6, "disbursement": 1 }
          }
        ]
      }
    ]
  }
}

Collecter un paiement (Collection)Collecting a payment (Collection)

Une Collection encaisse de l'argent depuis le mobile money d'un client vers votre wallet TekSafi. C'est une opération asynchrone : la réponse initiale confirme que la demande a été envoyée à l'opérateur, pas qu'elle a réussi.

A Collection pulls money from a customer's mobile money account into your TekSafi wallet. It's an asynchronous operation : the initial response confirms the request was sent to the operator, not that it succeeded.

POST/transactions/collection
Jeton + clé de collecteToken + collection key

En-têtes requis en plus de Authorization : X-Collection-Key: <votre collectionKey>.

Required header on top of Authorization : X-Collection-Key: <your collectionKey>.

Corps de la requêteRequest body
ChampFieldTypeRequisRequiredDescriptionDescription
countryCodestringouiyesEx. E.g. CG
paymentMethodCodestringouiyesEx. E.g. MTN_MOMO_COG — voirsee vos moyens disponiblesyour available methods
amountnumberouiyesMinimum Minimum 0.01, dans l'unité de la devisein the currency's unit
currencystringouiyesDoit correspondre à la devise du marchéMust match the market's currency
customerInfo.phoneNumberstringoui pour mobile moneyyes for mobile moneyVoirSee formats de téléphonephone number formats
referencestringnonnoVotre identifiant unique — rejouer la même reference renvoie la transaction existante au lieu d'en créer une seconde (idempotence)Your own unique identifier — replaying the same reference returns the existing transaction instead of creating a second one (idempotency)
metadataobjectnonnoLibre, restitué tel quelFree-form, echoed back as-is
RequêteRequest
POST /transactions/collection
X-Collection-Key: a2f1c9e4-...

{
  "countryCode": "CG",
  "paymentMethodCode": "MTN_MOMO_COG",
  "amount": 5000,
  "currency": "XAF",
  "customerInfo": { "phoneNumber": "242061234567" },
  "reference": "commande-48213"
}
RéponseResponse · 201
{
  "id": "985f19c3-11bc-422a-b731-c97ccb0e5e20",
  "reference": "commande-48213",
  "status": "PENDING",
  "amount": "5000.00",
  "currency": "XAF",
  "providerReference": "367ea115-37ce-4932-a69a-fbfe0e59384f",
  "createdAt": "2026-08-14T19:37:41.897Z",
  "customerInfo": { "phoneNumber": "242061234567" }
}

Ce qui se passe ensuiteWhat happens next

Le client reçoit une invite de confirmation (code PIN) sur son téléphone. Vous devez ensuite vérifier le statut final — voir Statut d'une transaction. Ne considérez jamais un encaissement comme réussi sur la seule foi de la réponse 201 : elle signifie "en cours", pas "payé".

The customer gets a PIN confirmation prompt on their phone. You then need to check the final status — see Transaction status. Never treat a collection as successful just because you got a 201 : it means "in progress", not "paid".

Calcul des fraisFee calculation

À la confirmation, votre wallet est crédité du montant net de deux commissions définies sur le tarif marché (configurées par un admin) : la commission agrégateur et la commission plateforme, chacune un pourcentage du montant brut.

On confirmation, your wallet is credited the amount net of two commissions defined on the market rate (configured by an admin) : the aggregator commission and the platform commission, each a percentage of the gross amount.

ÉtapeStepCalculCalculationExempleExample (5 000 XAF, 4%+2%)
Montant brutGross amountamount5 000
Commission agrégateurAggregator commissionamount × aggregatorCollectionRate / 100− 200
Commission plateformePlatform commissionamount × platformCollectionRate / 100− 100
Crédité sur votre walletCredited to your walletmontant − les deux commissionsamount − both commissions4 700 XAF

Formats de numéro de téléphonePhone number formats

Chaque moyen de paiement mobile money porte sa propre règle de validation (regexValidation), propre à son pays. TekSafi Pay n'est pas limité au Congo : de nouveaux marchés sont activés au fil du temps, chacun avec son propre format. Ne codez jamais un format en dur dans votre intégration — récupérez-le systématiquement via GET /applications/markets-payment-methods, qui reste la seule source à jour pour les marchés auxquels votre compte est relié.

Every mobile money payment method carries its own validation rule (regexValidation), specific to its country. TekSafi Pay isn't limited to Congo : new markets are activated over time, each with its own format. Never hardcode a format in your integration — always fetch it via GET /applications/markets-payment-methods, which remains the only up-to-date source for the markets your account is linked to.

À titre d'illustration du principe général (indicatif pays + préfixe opérateur local conservé, sans +), voici le marché Congo-Brazzaville :

As an illustration of the general pattern (country code + local operator prefix kept, no +), here is the Congo-Brazzaville market :

OpérateurOperatorPréfixe localLocal prefixFormat attenduExpected formatExempleExample
MTN CongoMTN Congo06242 + 06 + 7 chiffres (12 au total, pas de digits (12 total, no +)242061234567
Airtel CongoAirtel Congo04 ouor 05242 + 04/05 + 7 chiffresdigits242051234567
i

Le zéro local est conservé — on n'envoie pas un format international "sans zéro" (24261234567). C'est l'erreur la plus fréquente à l'intégration. D'autres marchés (avec leurs propres règles) s'ajoutent à mesure qu'ils sont activés — cette page n'est pas mise à jour à chaque nouveau marché, seul l'endpoint ci-dessus fait foi.

The local zero is kept — you don't send a "no-zero" international format (24261234567). This is the single most common integration mistake. More markets (each with their own rules) are added as they're activated — this page isn't updated for every new market, only the endpoint above is authoritative.

Vérifier le statut d'une transactionChecking a transaction's status

GET/transactions/callback/:reference
JetonToken

:reference est la reference fournie (ou générée) à la création. Interrogez cette route par intervalles réguliers (quelques secondes) jusqu'à obtenir un statut final.

:reference is the reference you supplied (or that was generated) at creation. Poll this route at regular intervals (a few seconds) until you get a final status.

PENDING → PROCESSING → SUCCESS ouor FAILED
RéponseResponse · 200 (succèssuccess)
{
  "id": "985f19c3-11bc-422a-b731-c97ccb0e5e20",
  "reference": "commande-48213",
  "status": "SUCCESS",
  "amount": "5000.00",
  "currency": "XAF",
  "providerReference": "367ea115-37ce-4932-a69a-fbfe0e59384f",
  "completedAt": "2026-08-14T19:39:57.453Z",
  "type": "collection"
}

WebhooksWebhooks

Plutôt que d'interroger GET /transactions/callback/:reference en boucle, enregistrez une URL de webhook : TekSafi vous notifie automatiquement dès qu'une transaction atteint un état définitif.

Instead of polling GET /transactions/callback/:reference in a loop, register a webhook URL : TekSafi notifies you automatically as soon as a transaction reaches a final state.

PATCH/applications/webhook
JetonToken
Corps de la requêteRequest body
ChampFieldTypeRequisRequiredDescriptionDescription
webhookUrlstringouiyesURL HTTPS qui recevra les notificationsHTTPS URL that will receive notifications
regenerateSecretbooleannonnoForce la génération d'un nouveau secret de signature (invalide l'ancien)Forces generation of a new signing secret (invalidates the old one)
RequêteRequest
{
  "webhookUrl": "https://monapp.cg/webhooks/teksafi"
}
RéponseResponse · 200
{
  "success": true,
  "message": "Webhook enregistré.",
  "data": {
    "webhookUrl": "https://monapp.cg/webhooks/teksafi",
    "webhookSecret": "676e30a4-58ee-4eeb-a5ca-f0c54e582d10"
  }
}
!

Le webhookSecret n'est affiché qu'une seule fois, à la création ou à la régénération. Stockez-le côté serveur — il sert à vérifier que les requêtes viennent bien de TekSafi.

The webhookSecret is shown only once, at creation or regeneration. Store it server-side — it's what lets you verify requests genuinely come from TekSafi.

Ce que vous recevezWhat you receive

Une requête POST vers votre webhookUrl, pour chacun des quatre événements :

A POST request to your webhookUrl, for each of the four events :

ÉvénementEventDéclenché quandFired when
collection.successUn encaissement a été confirmé par l'opérateurA collection was confirmed by the operator
collection.failedUn encaissement a échoué ou a été refuséA collection failed or was declined
disbursement.successUn décaissement a été confirmé par l'agrégateurA disbursement was confirmed by the aggregator
disbursement.failedUn décaissement a échouéA disbursement failed
POST https://monapp.cg/webhooks/teksafi
{
  "event": "collection.success",
  "data": {
    "id": "985f19c3-11bc-422a-b731-c97ccb0e5e20",
    "reference": "commande-48213",
    "status": "SUCCESS",
    "amount": "5000.00",
    "currency": "XAF",
    "providerReference": "367ea115-37ce-4932-a69a-fbfe0e59384f",
    "completedAt": "2026-08-14T19:39:57.453Z",
    "type": "collection"
  },
  "timestamp": "2026-08-14T19:39:57.500Z"
}

Vérifier la signatureVerifying the signature

Chaque requête porte un en-tête X-TekSafi-Signature : un HMAC-SHA256 du corps JSON exact (tel quel, avant tout re-formatage), calculé avec votre webhookSecret. Recalculez-le et comparez avant de traiter la notification.

Every request carries an X-TekSafi-Signature header : an HMAC-SHA256 of the exact JSON body (as sent, before any reformatting), computed with your webhookSecret. Recompute it and compare before acting on the notification.

Node.js
const crypto = require("crypto");

function isValid(rawBody, signatureHeader, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return expected === signatureHeader;
}

Réessais & fiabilitéRetries & reliability

3 tentatives par notification (avec un court délai croissant entre chacune) si votre endpoint ne répond pas ou renvoie une erreur. Passé ce délai, la notification est abandonnée : elle n'est pas conservée en file d'attente pour un envoi ultérieur. Votre endpoint doit répondre 2xx rapidement — traitez la notification de façon asynchrone si besoin plutôt que de faire attendre la réponse.

3 attempts per notification (with a short increasing delay between each) if your endpoint doesn't respond or returns an error. After that, the notification is dropped : it is not queued for later delivery. Your endpoint should respond 2xx quickly — process the notification asynchronously if needed rather than making the response wait.

i

Les webhooks sont un raccourci pratique, pas une garantie de livraison. Gardez toujours GET /transactions/callback/:reference comme filet de sécurité pour les transactions dont vous n'auriez pas reçu de notification.

Webhooks are a convenience, not a delivery guarantee. Always keep GET /transactions/callback/:reference as a safety net for transactions you never got notified about.

Décaisser (Disbursement)Payout (Disbursement)

Un Décaissement envoie de l'argent depuis votre wallet TekSafi vers un client (mobile money) ou un compte bancaire. Comme la Collection, c'est une opération asynchrone : fonctionne à l'identique en mode Sandbox (simulateur) et en mode Live (agrégateur réel) — aucun changement de contrat entre les deux.

A Disbursement sends money out from your TekSafi wallet to a customer (mobile money) or bank account. Like Collection, it's an asynchronous operation : it works identically in Sandbox mode (simulator) and Live mode (real aggregator) — no contract change between the two.

i

Le décaissement doit être activé explicitement pour votre application (disbursementAllowed, voir Authentification) et nécessite une clé dédiée, distincte de la clé de collecte.

Disbursement must be explicitly enabled for your application (disbursementAllowed, see Authentication) and requires a dedicated key, separate from your collection key.

POST/transactions/disbursement
Jeton + clé de décaissementToken + disbursement key

En-têtes requis en plus de Authorization : X-Disbursement-Key: <votre disbursementKey>.

Required header on top of Authorization : X-Disbursement-Key: <your disbursementKey>.

Corps de la requêteRequest body
ChampFieldTypeRequisRequiredDescriptionDescription
countryCodestringouiyesEx. E.g. CG
paymentMethodCodestringouiyesEx. E.g. ORANGE_MONEY — voirsee vos moyens disponiblesyour available methods
amountnumberouiyesMinimum Minimum 0.01 — montant effectivement reçu par le destinataire (les frais s'ajoutent, voir plus bas)amount the recipient actually receives (fees are added on top, see below)
currencystringouiyesDoit correspondre à la devise du marchéMust match the market's currency
recipientInfo.phoneNumberstringoui pour mobile moneyyes for mobile moneyVoirSee formats de téléphonephone number formats
referencestringnonnoVotre identifiant unique — rejouer la même reference renvoie la transaction existante au lieu d'en créer une seconde (idempotence)Your own unique identifier — replaying the same reference returns the existing transaction instead of creating a second one (idempotency)
metadataobjectnonnoLibre, restitué tel quelFree-form, echoed back as-is
RequêteRequest
POST /transactions/disbursement
X-Disbursement-Key: d9e2b7a1-...

{
  "countryCode": "CG",
  "paymentMethodCode": "ORANGE_MONEY",
  "amount": 3000,
  "currency": "XAF",
  "recipientInfo": { "phoneNumber": "242061234567" },
  "reference": "remboursement-9910"
}
RéponseResponse · 201
{
  "id": "12ab34cd-56ef-78a9-bc01-d2e3f4a5b6c7",
  "reference": "remboursement-9910",
  "status": "PROCESSING",
  "amount": "3000.00",
  "currency": "XAF",
  "providerReference": "9c1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
  "createdAt": "2026-08-14T19:37:41.897Z",
  "recipientInfo": { "phoneNumber": "242061234567" }
}

Ce qui se passe ensuiteWhat happens next

Votre wallet est débité du montant + frais avant l'appel à l'agrégateur (solde insuffisant → erreur 400, rien n'est débité). Le statut démarre directement à PROCESSING (pas de PENDING intermédiaire, contrairement à la Collection). Vérifiez le statut final via le même endpoint de statut ou via webhook.

Your wallet is debited the amount + fees before calling the aggregator (insufficient balance → 400 error, nothing gets debited). Status starts directly at PROCESSING (no intermediate PENDING, unlike Collection). Check the final status via the same status endpoint or via webhook.

Calcul des fraisFee calculation

Contrairement à la Collection, les frais s'ajoutent au montant demandé au lieu d'en être déduits : le destinataire reçoit le montant plein, et votre wallet est débité du montant + les deux commissions (agrégateur et plateforme, définies sur le tarif marché).

Unlike Collection, fees are added to the requested amount instead of being deducted from it : the recipient gets the full amount, and your wallet is debited the amount + both commissions (aggregator and platform, defined on the market rate).

ÉtapeStepCalculCalculationExempleExample (3 000 XAF, 4%+2%)
Montant reçu par le destinataireAmount received by the recipientamount3 000
Commission agrégateurAggregator commissionamount × aggregatorDisbursementRate / 100+ 120
Commission plateformePlatform commissionamount × platformDisbursementRate / 100+ 60
Débité de votre walletDebited from your walletmontant + les deux commissionsamount + both commissions3 180 XAF

Historique & statistiquesHistory & statistics

GET/transactions/application
JetonToken
Paramètres de requête (tous optionnels)Query parameters (all optional)
ChampFieldDescriptionDescription
typecollection ouor disbursement
statusPENDING·PROCESSING·SUCCESS·FAILED·REVERSED
startDate / endDateISO 8601
limitdéfaut 50default 50
RéponseResponse · 200
{
  "success": true,
  "data": [ { "id": "...", "status": "SUCCESS", "amount": "5000.00", "..." : "..." } ],
  "meta": { "total": 42, "totalPages": 1, "page": 1, "limite": 50 }
}
GET/transactions/stats/by-date?timeRange=30d
JetonToken

timeRange requis : 7d · 30d · 3m.

timeRange required : 7d · 30d · 3m.

RéponseResponse · 200
{
  "success": true,
  "data": {
    "stat": [ { "date": "2026-08-01", "collection": 3, "disbursement": 0 } ],
    "volume": { "collection": 42, "disbursement": 0 },
    "growth": { "collection": 12.5, "disbursement": 0 }
  }
}

Solde & walletBalance & wallet

GET/wallets/with-payment-methods
JetonToken

Renvoie chacun de vos wallets (un par marché/devise) avec les moyens de paiement actifs et les taux qui s'y appliquent.

Returns each of your wallets (one per market/currency) with the active payment methods and rates that apply to it.

RéponseResponse · 200
[
  {
    "id": "431a6abc-1cf5-44bf-b2b4-32bf85f7283a",
    "balance": "4700.00",
    "country": { "code": "CG" },
    "currency": { "code": "XAF" },
    "paymentMethods": [ { "code": "MTN_MOMO_COG", "rates": { "totalCollection": 6, "totalDisbursement": 1 } } ]
  }
]

Demander un retraitRequesting a withdrawal

1

Estimer les frais — POST /wallets/:walletId/withdrawal/fees avec { amount }. Renvoie fee, netAmount, et si votre solde suffit.

Estimate the fee — POST /wallets/:walletId/withdrawal/fees with { amount }. Returns fee, netAmount, and whether your balance is sufficient.

2

Créer la demande — POST /wallets/withdrawal-requests. Le montant est débité de votre wallet immédiatement ; la demande passe ensuite en traitement côté TekSafi.

Create the request — POST /wallets/withdrawal-requests. The amount is debited from your wallet immediately; the request then goes into processing on TekSafi's side.

3

Suivre l'avancement — GET /wallets/withdrawal-requests/:id/status, ou annuler tant qu'elle est encore PENDING via PATCH /wallets/withdrawal-requests/:id/cancel (remboursement automatique du wallet).

Track progress — GET /wallets/withdrawal-requests/:id/status, or cancel while it's still PENDING via PATCH /wallets/withdrawal-requests/:id/cancel (automatic wallet refund).

POST/wallets/withdrawal-requests
JetonToken
Corps de la requêteRequest body
ChampFieldTypeRequisRequiredDescriptionDescription
walletIdstringouiyesDoit vous appartenir et être actifMust belong to you and be active
amountnumberouiyesMinimum absolu Absolute minimum 100
paymentDetailsobjectouiyesExactement l'un des deux : Exactly one of the two : mobileMoney ouor bankAccount
priorityenumnon — déf. NORMALno — def. NORMALLOW·NORMAL·HIGH·URGENT — influence le délai estiméaffects the estimated delay
RequêteRequest
{
  "walletId": "431a6abc-1cf5-44bf-b2b4-32bf85f7283a",
  "amount": 4000,
  "paymentDetails": {
    "mobileMoney": { "provider": "MTN_MOMO_COG", "phoneNumber": "242061234567" }
  }
}
RéponseResponse · 201
{
  "success": true,
  "message": "Demande de retrait créée, wallet débité",
  "data": { "id": "...", "status": "PENDING", "amount": "4000.00" }
}

Référence des erreursError reference

StatutStatusCauseCauseExempleExample
400Corps de requête invalide ou règle métier non respectéeInvalid request body or a business rule wasn't met{ "statusCode": 400, "message": "amount must not be less than 0.01", "error": "Bad Request" }
401Jeton absent, expiré, ou de mauvais type (ex. jeton "email" utilisé sur une route "apikey")Missing or expired token, or the wrong type (e.g. an "email" token used on an "apikey" route){ "statusCode": 401, "message": "This route requires apikey authentication" }
403Compte authentifié mais rôle insuffisant (route réservée ADMIN)Authenticated, but insufficient role (route reserved for ADMIN){ "statusCode": 403, "message": "Cette action nécessite le rôle ADMIN." }
404Ressource introuvable (marché, moyen de paiement, transaction…)Resource not found (market, payment method, transaction…)—
429Trop de demandes de code OTP (max 5/heure)Too many OTP code requests (max 5/hour)"Trop de tentatives. Veuillez attendre 1 heure."

Les erreurs de validation de champ renvoient un tableau de messages, un par règle non respectée :

Field validation errors return an array of messages, one per failed rule :

400 — validationvalidation
{
  "statusCode": 400,
  "message": [
    "amount must not be less than 0.01",
    "currency must be a string"
  ],
  "error": "Bad Request"
}

Format des réponsesResponse format

La majorité des routes de lecture/écriture (comptes, transactions, wallet) renvoient une enveloppe standard :

Most read/write routes (accounts, transactions, wallet) return a standard envelope :

Enveloppe standardStandard envelope
{
  "success": true,
  "message": "...",
  "data": { }
}

Sur certaines routes de configuration, la réponse est directement l'objet créé/modifié, sans enveloppe — c'est indiqué à chaque endpoint de cette documentation par l'exemple de réponse fourni. En cas de doute, fiez-vous toujours à l'exemple, pas à une règle générale.

On some configuration routes, the response is directly the created/updated object, with no envelope — this is shown at every endpoint in this documentation via the response example provided. When in doubt, always trust the example, not a general rule.