Encaisser un client (payin)
Un payin débite le compte mobile money d'un client et crédite votre solde MoyaPay.
POST /payin
Requiert un jeton Bearer.
Corps de la requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
refercence_cl | string | oui | Votre référence marchand. Doit correspondre au compte du jeton |
business_code | string | oui | Code business fourni par MoyaPay. Doit appartenir à votre compte |
country_code | string | oui | Pays de la transaction : CI, SN, BF, CM, BN, RDC, CB, GMB |
payment_method | string | oui | Code du moyen de paiement, voir Moyens de paiement |
merchant_transaction_id | string | oui | Votre identifiant de transaction, unique |
amount | number | oui | Montant, en nombre JSON (pas une chaîne). Voir Limites |
currency | string | oui | Devise du pays de la transaction, par exemple XOF. À choisir dans le tableau Devises par pays |
telephone | string | oui | Numéro du client, en chaîne. Voir Limites |
successUrl | string | oui | URL de redirection après un paiement réussi (moyens avec redirection, comme Wave) |
failedUrl | string | oui | URL de redirection après un paiement échoué |
notifyUrl | string | oui | Votre URL de notification. Voir la note ci-dessous |
otp_code | string | selon le moyen | Obligatoire pour OM_CI (Orange Money Côte d'Ivoire) : code à usage unique généré par le client |
notifyUrlLe champ est obligatoire, mais les callbacks sont aujourd'hui envoyés à l'URL de callback enregistrée sur votre compte marchand par MoyaPay (une URL pour les payins, une autre pour les payouts), pas à la valeur transmise dans notifyUrl.
Exemple
- cURL
- Node.js
- PHP
- Python
curl -X POST https://services.moya-pay.com/service/api/v1/payin \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"refercence_cl": "CL-123456",
"business_code": "MYP-000000-ABCDEF",
"country_code": "CI",
"payment_method": "WAVE_CI",
"merchant_transaction_id": "COMMANDE-2026-000123",
"amount": 1000,
"currency": "XOF",
"telephone": "0505000000",
"successUrl": "https://boutique.example.com/paiement/succes",
"failedUrl": "https://boutique.example.com/paiement/echec",
"notifyUrl": "https://boutique.example.com/api/moyapay/notify"
}'
const res = await fetch('https://services.moya-pay.com/service/api/v1/payin', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
refercence_cl: 'CL-123456',
business_code: 'MYP-000000-ABCDEF',
country_code: 'CI',
payment_method: 'WAVE_CI',
merchant_transaction_id: 'COMMANDE-2026-000123',
amount: 1000,
currency: 'XOF',
telephone: '0505000000',
successUrl: 'https://boutique.example.com/paiement/succes',
failedUrl: 'https://boutique.example.com/paiement/echec',
notifyUrl: 'https://boutique.example.com/api/moyapay/notify',
}),
});
const body = await res.json();
if (!body.success) throw new Error(body.description || body.message);
console.log(body.data.status, body.data.payment_url);
<?php
$payload = [
'refercence_cl' => 'CL-123456',
'business_code' => 'MYP-000000-ABCDEF',
'country_code' => 'CI',
'payment_method' => 'WAVE_CI',
'merchant_transaction_id' => 'COMMANDE-2026-000123',
'amount' => 1000,
'currency' => 'XOF',
'telephone' => '0505000000',
'successUrl' => 'https://boutique.example.com/paiement/succes',
'failedUrl' => 'https://boutique.example.com/paiement/echec',
'notifyUrl' => 'https://boutique.example.com/api/moyapay/notify',
];
$ch = curl_init('https://services.moya-pay.com/service/api/v1/payin');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($body['success'])) {
throw new Exception($body['description'] ?? $body['message'] ?? 'Erreur MoyaPay');
}
import requests
resp = requests.post(
"https://services.moya-pay.com/service/api/v1/payin",
headers={"Authorization": f"Bearer {token}"},
json={
"refercence_cl": "CL-123456",
"business_code": "MYP-000000-ABCDEF",
"country_code": "CI",
"payment_method": "WAVE_CI",
"merchant_transaction_id": "COMMANDE-2026-000123",
"amount": 1000,
"currency": "XOF",
"telephone": "0505000000",
"successUrl": "https://boutique.example.com/paiement/succes",
"failedUrl": "https://boutique.example.com/paiement/echec",
"notifyUrl": "https://boutique.example.com/api/moyapay/notify",
},
timeout=30,
)
body = resp.json()
if not body.get("success"):
raise RuntimeError(body.get("description") or body.get("message"))
Réponse
{
"status": 201,
"success": true,
"code": 200,
"message": "TRANSACTION IS INITIATED SUSSESSFULLY",
"data": {
"status": "PENDING",
"transaction_id": "COMMANDE-2026-000123",
"payment_url": "https://pay.wave.com/c/..."
}
}
| Champ | Description |
|---|---|
success | true si la demande est acceptée. C'est ce champ qu'il faut tester |
data.status | Statut initial de la transaction, en général PENDING |
data.transaction_id | Votre merchant_transaction_id, à conserver pour suivre la transaction |
data.payment_url | Selon le moyen de paiement. URL vers laquelle rediriger le client pour valider le paiement (Wave notamment) |
data.deepLinks, data.validFor | Selon le moyen de paiement. Lien d'ouverture de l'application de l'opérateur et durée de validité |
data.msg | Selon le moyen de paiement. Instruction à afficher au client |
Le champ status de premier niveau vaut 201 alors que le statut HTTP est 200 : ne vous appuyez pas sur cette valeur. Le texte de message peut aussi varier selon l'opérateur : ne l'analysez pas dans votre code. Testez success, puis lisez data.status.
Après la réponse
- Selon le moyen de paiement, redirigez le client vers
data.payment_urlou affichez-lui l'instruction (data.msg) pour qu'il valide sur son téléphone. - Attendez le callback, ou interrogez le statut de la transaction.
Règles de validation
merchant_transaction_iddoit être inédit. Un identifiant déjà utilisé renvoie une erreur400. L'unicité est vérifiée sur toute la plateforme : choisissez des identifiants distinctifs.- Une transaction identique (même montant, même numéro, même type) encore en cours depuis moins d'une minute est refusée avec
An identical transaction is already in progress. Please wait.Attendez la fin de la première, ou changez le montant. - Le moyen de paiement doit être activé sur votre compte, sinon la réponse est
Marchand not have provider.
Les erreurs possibles sont listées dans Erreurs.
Si l'initiation échoue chez l'opérateur (Impossible to make the transaction, HTTP 500), la transaction est tout de même enregistrée. N'envoyez pas de nouveau le même merchant_transaction_id : vérifiez d'abord son statut, puis créez une nouvelle transaction avec un nouvel identifiant si nécessaire.