Introduction

L'API CowemaPay vous permet d'accepter des paiements Mobile Money (MTN MoMo, Airtel Money) dans vos applications. L'API suit les conventions REST et retourne du JSON.

URL de base :

https://pay.cowema.org/api/v1
En environnement sandbox, vous pouvez aussi utiliser https://pay.cowema.org/api/v1 si vous travaillez en local.
OpenAPI / Swagger Fichier .http (VS Code / JetBrains) Voir le JSON
Importez openapi.json dans Bruno, Postman ou Insomnia. Ou utilisez le fichier .http directement dans VS Code (REST Client) ou JetBrains.

Demarrage rapide

1. Creez votre compte

Rendez-vous sur le tableau de bord et creez un compte. Vous serez invite a creer une organisation.

2. Creez une application

Dans le menu Applications, cliquez sur New application. Donnez-lui un nom et configurez vos URLs de webhook si necessaire.

3. Generez vos cles API

Sur la liste des applications, cliquez sur l'icone cle a cote de votre application, puis Cles API (test). Une modale affichera vos cles :

ClePrefixeVisibilite
Cle publiquepk_test_...Visible a tout moment dans le dashboard
Cle secretesk_test_...Affichee une seule fois a la generation
Copiez votre cle secrete immediatement. Elle ne sera plus jamais affichee. Si vous la perdez, generez-en une nouvelle (l'ancienne sera invalidee).

4. Faites votre premier appel

Testez avec un paiement sandbox :

curl
curl -X POST https://pay.cowema.org/api/v1/payments \
  -H "Authorization: Bearer sk_test_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5000,
    "country": "CG",
    "phone_number": "054553499",
    "provider": "mtn_momo"
  }'

Le numero 054553499 simule un paiement reussi en sandbox.

Flow de paiement API

Votre serveur CowemaPay Fournisseur Mobile Money Votre serveur CowemaPay Fournisseur Mobile Money POST /api/v1/payments 201 {status: "pending"} requestToPay() Le client confirme sur son telephone Callback status → "successful" Webhook POST {event: "payment.successful"} 200 OK

Authentification

Toutes les requetes API doivent inclure votre cle secrete dans le header Authorization.

Header d'authentification
Authorization: Bearer sk_test_votre_cle_secrete
Ne partagez jamais votre cle secrete (sk_). Elle donne un acces complet a votre compte. Utilisez la cle publique (pk_) cote frontend.
Type de clePrefixeUsage
Cle publique testpk_test_Identification cote client (sandbox)
Cle secrete testsk_test_Requetes API (sandbox)
Cle publique livepk_live_Identification cote client (production)
Cle secrete livesk_live_Requetes API (production)

Mode sandbox

Les cles sk_test_ activent automatiquement le mode sandbox. Aucun appel reel n'est fait aux fournisseurs. Utilisez ces numeros de test :

*****0000 → Paiement reussi
*****0002 → Fonds insuffisants
*****0003 → Timeout fournisseur
Tout autre → Paiement reussi

Creer un paiement

POST /api/v1/payments

Initie une demande de paiement Mobile Money. Le client recevra une notification sur son telephone pour confirmer.

Idempotence : Ajoutez le header Idempotency-Key pour eviter les doublons en cas de retry. En savoir plus
ParametreTypeDescription
amountintegerrequisMontant en unite minimale (ex: 5000 = 5 000 XAF)
countrystringrequisCode pays ISO 2 lettres (ex: CG)
currencystringoptionnelCode devise ISO (ex: XAF) -- deduit automatiquement du pays
phone_numberstringrequisNumero de telephone du payeur
providerstringrequismtn_momo ou airtel_money
metadataobjectoptionnelDonnees personnalisees (ex: order_id)
curl
curl -X POST https://pay.cowema.org/api/v1/payments \
  -H "Authorization: Bearer sk_test_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: votre-cle-unique" \
  -d '{
    "amount": 5000,
    "country": "CG",
    "phone_number": "054553499",
    "provider": "mtn_momo",
    "metadata": {"order_id": "ORD-123"}
  }'
201 -- Paiement cree
{
  "data": {
    "id": "9f8a2b3c-...",
    "type": "collection",
    "provider": "mtn_momo",
    "amount": 5000,
    "currency": "XAF",
    "country": "CG",
    "phone_number": "054553499",
    "status": "pending",
    "environment": "test",
    "metadata": { "order_id": "ORD-123" },
    "created_at": "2026-03-29T18:00:00+00:00"
  }
}
401 -- Non authentifie
{
  "error": "Missing API key.",
  "code": "missing_api_key"
}
422 -- Erreur de validation
{
  "message": "The amount field is required.",
  "errors": {
    "amount": ["The amount field is required."],
    "provider": ["The selected provider is invalid."]
  }
}
429 -- Rate limit depasse
{
  "message": "Too Many Attempts."
}

Voir un paiement

GET /api/v1/payments/{id}

Recupere les details d'un paiement par son identifiant.

curl
curl https://pay.cowema.org/api/v1/payments/PAYMENT_UUID \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
200 -- Paiement trouve
{
  "data": {
    "id": "9f8a2b3c-...",
    "type": "collection",
    "status": "successful",
    // ... memes champs que la creation
  }
}
404 -- Transaction introuvable
{
  "error": "Transaction not found.",
  "code": "not_found"
}

Lister les paiements

GET /api/v1/payments

Retourne la liste paginee de vos paiements. Filtrable par statut, fournisseur et environnement.

ParametreTypeDescription
statusstringfiltrepending, processing, successful, failed, cancelled
providerstringfiltremtn_momo ou airtel_money
environmentstringfiltrelive ou test
per_pageintegerfiltreNombre de resultats (max 100)
curl
curl "https://pay.cowema.org/api/v1/payments?status=successful&per_page=10" \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
200 -- Liste paginee
{
  "data": [
    {
      "id": "9f8a2b3c-...",
      "type": "collection",
      "amount": 5000,
      "status": "successful",
      // ...
    },
    // ... autres transactions
  ],
  "links": {
    "first": "...?page=1",
    "last": "...?page=3",
    "prev": null,
    "next": "...?page=2"
  },
  "meta": {
    "current_page": 1,
    "per_page": 10,
    "total": 25,
    "last_page": 3
  }
}
422 -- Filtre invalide
{
  "message": "The selected status is invalid.",
  "errors": {
    "status": ["The selected status is invalid."]
  }
}

Creer un remboursement

POST /api/v1/refunds

Rembourse un paiement reussi. Le montant est reverse sur le compte Mobile Money du payeur.

Idempotence : Ajoutez le header Idempotency-Key pour eviter les doublons en cas de retry. En savoir plus
ParametreTypeDescription
payment_idstringrequisUUID du paiement a rembourser
amountintegerrequisMontant a rembourser
curl
curl -X POST https://pay.cowema.org/api/v1/refunds \
  -H "Authorization: Bearer sk_test_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: votre-cle-unique" \
  -d '{
    "payment_id": "PAYMENT_UUID",
    "amount": 5000
  }'
201 -- Remboursement cree
{
  "data": {
    "id": "b7c4e1f2-...",
    "type": "refund",
    "status": "pending",
    // ... memes champs qu'une transaction
  }
}
422 -- Transaction non remboursable
{
  "error": "Original transaction not found or not refundable.",
  "code": "not_refundable"
}

Voir un remboursement

GET /api/v1/refunds/{id}
curl
curl https://pay.cowema.org/api/v1/refunds/REFUND_UUID \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
200 -- Remboursement trouve
{
  "data": {
    "id": "b7c4e1f2-...",
    "type": "refund",
    "provider": "mtn_momo",
    "amount": 5000,
    "currency": "XAF",
    "status": "successful",
    "environment": "test",
    "created_at": "2026-03-29T18:05:00+00:00"
  }
}
404 -- Remboursement introuvable
{
  "error": "Refund not found.",
  "code": "not_found"
}

Creer une session Checkout

POST /api/v1/checkout/sessions

Cree une session de paiement hebergee. Redirigez votre client vers l'URL retournee.

Idempotence : Ajoutez le header Idempotency-Key pour eviter les doublons en cas de retry. En savoir plus
ParametreTypeDescription
amountintegerrequisMontant
countrystringrequisCode pays ISO 2 lettres (ex: CG)
currencystringoptionnelCode devise -- deduit du pays si omis
success_urlstringrequisURL de redirection apres succes
cancel_urlstringrequisURL de redirection si annule
descriptionstringoptionnelDescription affichee au client
metadataobjectoptionnelDonnees personnalisees (ex: order_id)
curl
curl -X POST https://pay.cowema.org/api/v1/checkout/sessions \
  -H "Authorization: Bearer sk_test_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: votre-cle-unique" \
  -d '{
    "amount": 10000,
    "country": "CG",
    "description": "Abonnement Premium",
    "success_url": "https://votresite.com/success",
    "cancel_url": "https://votresite.com/cancel"
  }'
201 -- Session creee
{
  "data": {
    "id": "cs_abc123...",
    "amount": 10000,
    "currency": "XAF",
    "country": "CG",
    "url": "https://pay.cowema.org/checkout/cs_abc123",
    "status": "open",
    "expires_at": "2026-03-29T19:00:00+00:00"
  }
}
422 -- Erreur de validation
{
  "message": "The success url field is required.",
  "errors": {
    "success_url": ["The success url field is required."]
  }
}

Voir une session checkout

GET /api/v1/checkout/sessions/{id}

Recupere le statut d'une session checkout. Utilisez cet endpoint pour verifier cote serveur si le paiement a abouti.

curl
curl https://pay.cowema.org/api/v1/checkout/sessions/SESSION_UUID \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
200 -- Session trouvee
{
  "data": {
    "id": "cs_abc123...",
    "amount": 10000,
    "currency": "XAF",
    "description": "Abonnement Premium",
    "url": "https://pay.cowema.org/checkout/cs_abc123",
    "status": "completed",
    "expires_at": "2026-03-29T19:00:00+00:00",
    "metadata": null,
    "created_at": "2026-03-29T18:00:00+00:00"
  }
}
404 -- Session introuvable
{
  "error": "Checkout session not found.",
  "code": "not_found"
}

Flow d'integration Checkout

Le checkout heberge est le moyen le plus simple d'accepter des paiements. Pas besoin de gerer le formulaire cote client.

1. Creez une session cote serveur

Appelez POST /api/v1/checkout/sessions depuis votre backend avec votre cle secrete.

2. Redirigez le client

Envoyez votre client vers l'URL data.url retournee dans la reponse.

3. Le client paie

Sur la page CowemaPay, il choisit son fournisseur (MTN/Airtel), entre son numero, et confirme.

4. Redirection automatique

Apres paiement, le client est redirige vers votre success_url ou cancel_url.

5. Verifiez cote serveur

Utilisez GET /api/v1/checkout/sessions/{id} ou les webhooks pour confirmer le paiement.

Diagramme

Votre serveur CowemaPay Client Votre serveur CowemaPay Client POST /api/v1/checkout/sessions 201 {url: "/checkout/xxx"} Redirect vers checkout URL Choisit provider + entre numero Confirmation sur telephone Redirect vers success_url Webhook POST {event: "payment.successful"}

Creer un decaissement

POST /api/v1/payouts

Initie un transfert d'argent vers un compte Mobile Money. Le montant est debite de votre solde marchand.

Idempotence : Ajoutez le header Idempotency-Key pour eviter les doublons en cas de retry. En savoir plus
ParametreTypeDescription
amountintegerrequisMontant en unite minimale (ex: 5000 = 5 000 XAF)
currencystringrequisCode devise ISO (ex: XAF)
countrystringrequisCode pays ISO 2 lettres (ex: CG)
providerstringrequismtn_momo ou airtel_money
phone_numberstringrequisNumero de telephone du beneficiaire
metadataobjectoptionnelDonnees personnalisees (ex: order_id)

Statuts d'un decaissement

StatutDescription
pendingDecaissement cree, en attente de validation
approvedDecaissement approuve, pret a etre traite
processingTransfert en cours aupres du fournisseur
completedTransfert effectue avec succes
failedLe transfert a echoue
rejectedDecaissement rejete
curl
curl -X POST https://pay.cowema.org/api/v1/payouts \
  -H "Authorization: Bearer sk_test_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: votre-cle-unique" \
  -d '{
    "amount": 5000,
    "currency": "XAF",
    "country": "CG",
    "provider": "mtn_momo",
    "phone_number": "066000001"
  }'
201 -- Decaissement cree
{
  "data": {
    "id": "d4e5f6a7-...",
    "type": "payout",
    "provider": "mtn_momo",
    "amount": 5000,
    "currency": "XAF",
    "country": "CG",
    "phone_number": "066000001",
    "status": "pending",
    "environment": "test",
    "metadata": null,
    "created_at": "2026-03-31T10:00:00+00:00"
  }
}
422 -- Solde insuffisant
{
  "error": "Insufficient balance for this payout.",
  "code": "insufficient_balance"
}
422 -- Erreur de validation
{
  "message": "The amount field is required.",
  "errors": {
    "amount": ["The amount field is required."]
  }
}

Lister les decaissements

GET /api/v1/payouts

Retourne la liste paginee de vos decaissements. Filtrable par statut.

ParametreTypeDescription
statusstringfiltrepending, approved, processing, completed, failed, rejected
per_pageintegerfiltreNombre de resultats (max 100)
curl
curl "https://pay.cowema.org/api/v1/payouts?status=completed&per_page=10" \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
200 -- Liste paginee
{
  "data": [
    {
      "id": "d4e5f6a7-...",
      "type": "payout",
      "amount": 5000,
      "status": "completed",
      // ...
    }
  ],
  "links": { // ... pagination },
  "meta": {
    "current_page": 1,
    "per_page": 10,
    "total": 8,
    "last_page": 1
  }
}

Voir un decaissement

GET /api/v1/payouts/{id}

Recupere les details d'un decaissement par son identifiant.

curl
curl https://pay.cowema.org/api/v1/payouts/PAYOUT_UUID \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
200 -- Decaissement trouve
{
  "data": {
    "id": "d4e5f6a7-...",
    "type": "payout",
    "provider": "mtn_momo",
    "amount": 5000,
    "currency": "XAF",
    "country": "CG",
    "phone_number": "066000001",
    "status": "completed",
    "environment": "test",
    "created_at": "2026-03-31T10:00:00+00:00"
  }
}
404 -- Decaissement introuvable
{
  "error": "Payout not found.",
  "code": "not_found"
}

Solde marchand

GET /api/v1/merchant/balance

Retourne le solde disponible de votre compte marchand, ventile par devise.

curl
curl https://pay.cowema.org/api/v1/merchant/balance \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
200 -- Solde recupere
{
  "data": [
    {
      "currency": "XAF",
      "available_balance": 15885960,
      "pending_balance": 0
    }
  ]
}

Idempotence

Tous les endpoints POST acceptent un header Idempotency-Key pour eviter les doublons en cas de retry reseau.

Header d'idempotence
Idempotency-Key: votre-cle-unique-uuid

Fonctionnement

ScenarioComportement
Meme cle + meme bodyRetourne la reponse mise en cache (validite 30 jours)
Meme cle + body differentRetourne une erreur 409 Conflict
Pas de headerRequete traitee normalement (pas d'idempotence)
curl -- Exemple avec idempotence
curl -X POST https://pay.cowema.org/api/v1/payments \
  -H "Authorization: Bearer sk_test_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "amount": 5000,
    "country": "CG",
    "phone_number": "054553499",
    "provider": "mtn_momo"
  }'
409 -- Conflit d'idempotence
{
  "error": "A request with this idempotency key already exists with a different body.",
  "code": "idempotency_conflict"
}
Le header Idempotency-Key est optionnel. Utilisez un UUID v4 unique par requete pour garantir l'unicite.

Securite

CowemaPay propose plusieurs mecanismes de securite configurables par application.

IP Whitelisting

Vous pouvez restreindre les appels API a une liste d'adresses IP autorisees. Configurez les IPs dans le dashboard, sur la page d'edition de votre application.

403 -- IP non autorisee
{
  "error": "Votre adresse IP n'est pas autorisée pour cette application.",
  "code": "ip_not_whitelisted"
}

Rate Limiting

Par defaut, l'API autorise 100 requetes par minute par application. Cette limite est configurable par organisation.

HeaderDescription
X-RateLimit-LimitNombre maximum de requetes par minute
X-RateLimit-RemainingNombre de requetes restantes
Retry-AfterSecondes avant la prochaine fenetre (si limite atteinte)

KYC Gate

Le mode live necessite une verification KYC valide pour votre organisation. Les cles sk_live_ sont inutilisables tant que le KYC n'est pas approuve.

403 -- KYC requis
{
  "error": "La vérification KYC est requise pour utiliser le mode live.",
  "code": "kyc_verification_required"
}

Webhooks sortants

CowemaPay envoie des notifications HTTP (webhooks) vers votre webhook_url a chaque changement de statut d'un paiement ou d'un decaissement.

Signature

Chaque webhook inclut un header X-CowemaPay-Signature contenant un HMAC-SHA256 du body brut, signe avec votre webhook_secret.

PHP — Vérification de signature
// Verifiez toujours la signature avant de traiter l'evenement
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_COWEMAPAY_SIGNATURE'];
$secret = 'votre_webhook_secret';

$expected = hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Signature invalide');
}

$event = json_decode($payload, true);
// Traitez l'evenement...

Types d'evenements

EvenementDescription
payment.successfulUn paiement a ete confirme
payment.failedUn paiement a echoue
refund.successfulUn remboursement a ete confirme
refund.failedUn remboursement a echoue
payout.completedUn decaissement a ete effectue
payout.failedUn decaissement a echoue

Politique de retry

Si votre serveur ne repond pas avec un code 2xx, CowemaPay reessaie jusqu'a 3 fois avec un delai croissant :

TentativeDelai
1er retry60 secondes
2e retry5 minutes
3e retry30 minutes

Payload exemple

POST votre-webhook-url
// Headers
Content-Type: application/json
X-CowemaPay-Signature: a1b2c3d4e5...
X-CowemaPay-Event: payment.successful

// Body
{
  "event": "payment.successful",
  "data": {
    "id": "9f8a2b3c-...",
    "type": "collection",
    "amount": 5000,
    "currency": "XAF",
    "country": "CG",
    "phone_number": "054553499",
    "provider": "mtn_momo",
    "status": "successful",
    "environment": "test",
    "metadata": { "order_id": "ORD-123" },
    "created_at": "2026-03-29T18:00:00+00:00"
  },
  "timestamp": "2026-03-29T18:00:15+00:00"
}
Verifiez toujours la signature X-CowemaPay-Signature avant de traiter un webhook. Ne faites jamais confiance au contenu sans verification.

Solde fournisseur

Interroge directement le solde aupres du fournisseur Mobile Money.

GET /api/v1/balance?provider=mtn_momo
curl
curl "https://pay.cowema.org/api/v1/balance?provider=mtn_momo" \
  -H "Authorization: Bearer sk_test_VOTRE_CLE"
200 -- Solde recupere
{
  "data": {
    "available": 1000000,
    "currency": "XAF"
  }
}
422 -- Fournisseur invalide
{
  "message": "The selected provider is invalid.",
  "errors": {
    "provider": ["The selected provider is invalid."]
  }
}

Webhooks

CowemaPay envoie des webhooks a l'URL configuree dans votre application lorsqu'un evenement se produit.

Configuration

Dans le dashboard, editez votre application et renseignez l'URL du webhook. Un webhook_secret est genere automatiquement -- vous le trouverez sur la page d'edition de l'application, dans le champ Secret du webhook.

Evenements

EvenementDescription
payment.successfulUn paiement a ete confirme
payment.failedUn paiement a echoue
refund.successfulUn remboursement a ete confirme
refund.failedUn remboursement a echoue

Verification de la signature

Chaque webhook inclut un header X-CowemaPay-Signature contenant un HMAC SHA-256 du body avec votre webhook_secret.

PHP — Vérification
// Verifiez la signature du webhook
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_COWEMAPAY_SIGNATURE'];
$secret = 'votre_webhook_secret';

$expected = hash_hmac('sha256', $payload, $secret);

if (hash_equals($expected, $signature)) {
    // Webhook valide
    $event = json_decode($payload, true);
    // Traitez l'evenement...
}

Payload complet

Voici un exemple de payload envoye par CowemaPay :

POST votre-webhook-url
// Headers
Content-Type: application/json
X-CowemaPay-Signature: a1b2c3d4e5...
X-CowemaPay-Event: payment.successful

// Body
{
  "event": "payment.successful",
  "data": {
    "id": "9f8a2b3c-...",
    "type": "collection",
    "amount": 5000,
    "currency": "XAF",
    "country": "CG",
    "phone_number": "054553499",
    "provider": "mtn_momo",
    "status": "successful",
    "environment": "test",
    "metadata": { "order_id": "ORD-123" },
    "created_at": "2026-03-29T18:00:00+00:00"
  },
  "timestamp": "2026-03-29T18:00:15+00:00"
}

Retries

Si votre serveur ne repond pas avec un code 2xx, CowemaPay reessaie jusqu'a 3 fois avec un delai croissant : 1 minute, 5 minutes, 30 minutes.

Erreurs

L'API utilise les codes HTTP standards :

CodeDescription
200Succes
201Ressource creee
401Cle API manquante ou invalide
403Acces interdit (IP non autorisee, KYC requis)
404Ressource introuvable
409Conflit d'idempotence
422Erreur de validation / solde insuffisant
429Trop de requetes (rate limit)
500Erreur serveur
Exemple d'erreur 422
{
  "message": "The amount field is required.",
  "errors": {
    "amount": ["The amount field is required."]
  }
}