Encaisser un paiement
L'encaissement permet à vos clients de vous payer par Mobile Money via une page sécurisée Tchin. Le parcours se résume en 4 temps :
- Créer le paiement — votre serveur appelle l'API et reçoit une
payment_url. - Rediriger le client vers cette page de paiement.
- Le client choisit son pays, son opérateur, saisit son numéro et paie.
- Confirmation — le client est renvoyé directement sur votre site, et Tchin notifie votre
callback_url(webhook = source de vérité).
Endpoint
POST /api/v1/payments
| Champ | Type | Requis | Description |
|---|---|---|---|
amount | entier | oui | Montant en FCFA (XOF), min 100. |
description | texte | non | Libellé affiché au client (max 255). |
env | texte | non | test (défaut) ou live. |
return_url | URL | non | Page du marchand où renvoyer le client. Si absent, retour automatique sur la page d'origine. |
cancel_url | URL | non | Page de retour en cas d'annulation. Défaut : return_url. |
callback_url | URL | non | Webhook de notification. Défaut : celui de l'app. |
Requête (cURL)
curl -X POST https://tchin.tech/api/v1/payments \
-H "TCHIN-PUBLIC-KEY: tchin_pk_xxxxxxxx" \
-H "TCHIN-PRIVATE-KEY: tchin_sk_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"description": "Commande #1024",
"env": "test",
"return_url": "https://monsite.com/merci",
"callback_url": "https://monsite.com/tchin/webhook"
}'
Réponse
{
"success": true,
"token": "a1b2c3d4e5f6",
"payment_url": "https://tchin.tech/pay/a1b2c3d4e5f6",
"env": "test"
}
| Champ | Description |
|---|---|
token | Référence unique du paiement. Mémorisez-la avec votre commande. |
payment_url | Page de paiement vers laquelle rediriger le client. |
Exemples par langage
PHP
<?php
function tchin_post($path, $body) {
$ch = curl_init('https://tchin.tech/api/v1/'.$path);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'TCHIN-PUBLIC-KEY: '.getenv('TCHIN_PUBLIC_KEY'),
'TCHIN-PRIVATE-KEY: '.getenv('TCHIN_SECRET_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($body),
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
return $res;
}
// 1) Créer le paiement (côté serveur)
$res = tchin_post('payments', [
'amount' => 5000, // FCFA (XOF), entier
'description' => 'Commande #1024',
'env' => 'live', // ou "test"
'return_url' => 'https://monsite.com/merci',
'callback_url' => 'https://monsite.com/tchin/webhook',
]);
// 2) Mémoriser $res['token'] avec votre commande, puis rediriger le client
header('Location: '.$res['payment_url']);
exit;
Node.js
// Node.js / Express
import express from 'express';
const app = express();
app.post('/payer', async (req, res) => {
const r = await fetch('https://tchin.tech/api/v1/payments', {
method: 'POST',
headers: {
'TCHIN-PUBLIC-KEY': process.env.TCHIN_PUBLIC_KEY,
'TCHIN-PRIVATE-KEY': process.env.TCHIN_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 5000,
description: 'Commande #1024',
env: 'live',
return_url: 'https://monsite.com/merci',
callback_url: 'https://monsite.com/webhook',
}),
});
const data = await r.json();
res.redirect(data.payment_url); // on envoie le client payer
});
Python
# Python (requests)
import os, requests
r = requests.post('https://tchin.tech/api/v1/payments',
headers={
'TCHIN-PUBLIC-KEY': os.environ['TCHIN_PUBLIC_KEY'],
'TCHIN-PRIVATE-KEY': os.environ['TCHIN_SECRET_KEY'],
},
json={
'amount': 5000,
'description': 'Commande #1024',
'env': 'live',
'return_url': 'https://monsite.com/merci',
'callback_url': 'https://monsite.com/webhook',
})
data = r.json()
payment_url = data['payment_url'] # rediriger le client vers cette URL
Rediriger le client
Après réception de la payment_url, redirigez le navigateur du client dessus (réponse HTTP 302, ou un simple lien/bouton). Le client effectue tout le paiement sur la page Tchin (choix opérateur, OTP, etc.) — vous n'avez rien d'autre à coder côté paiement.
Où définir le retour et le webhook ?
Deux endroits, selon vos besoins :
- À la création de l'application (menu API → champ « URL Webhook ») : cette URL est le
callback_urlpar défaut de tous les paiements de l'app. - À chaque paiement (
POST /api/v1/payments) : vous fournissezreturn_urlet, si besoin,callback_urlpour CE paiement (il remplace alors celui de l'app). Les deux sont optionnels.
Le retour du client
Une fois le paiement terminé (réussi ou annulé), Tchin n'affiche aucune page de remerciement : le client est renvoyé directement sur votre site, là où il se trouvait avant d'être redirigé — comme toute passerelle de paiement.
- Si vous avez fourni
return_url(et au besoincancel_url), le client y est renvoyé. - Sinon, Tchin le ramène automatiquement sur la page d'origine. Vous n'avez donc, le plus souvent, rien à définir.
Tchin ajoute deux paramètres à l'URL de retour :
| Paramètre | Valeur |
|---|---|
status | success (payé) ou cancel (annulé par le client). |
token | La référence du paiement (identique à celle reçue à la création). |
Exemple : https://votre-site.com/panier?status=success&token=ab12cd34ef
<?php
// Votre page return_url, appelée quand le client revient du paiement
$status = $_GET['status'] ?? null;
if ($status === 'success') {
// Afficher un écran "Merci".
// NB : validez/livrez la commande UNIQUEMENT via le webhook (source de vérité).
} elseif ($status === 'cancel') {
// Le client a annulé : afficher "Paiement annulé".
}
⚠️ Le retour client sert uniquement à l'affichage : le client peut fermer son navigateur avant d'y revenir. Pour valider et livrer une commande, fiez-vous toujours au webhook.
La notification serveur (callback_url / webhook)
Dès que le paiement est confirmé, Tchin envoie une requête POST à votre callback_url (ou au webhook de l'app). C'est la source de vérité : c'est là que vous marquez la commande payée. Détails et exemples sur la page Webhooks.
Applications mobiles (Android, iOS, Flutter…)
Le principe est identique aux sites web. Ne mettez jamais la clé secrète dans l'application : créez le paiement depuis votre backend, renvoyez la payment_url à l'app, puis ouvrez-la :
- Android — Chrome Custom Tabs (recommandé) ou une
WebView. - iOS —
SFSafariViewController/ASWebAuthenticationSessionou uneWKWebView. - Flutter —
flutter_web_auth_2,url_launcherouwebview_flutter.
Pour récupérer le client dans l'app, utilisez un deep link / lien universel comme return_url (ex. monapp://retour). L'app détecte ce retour et affiche l'écran adéquat ; la commande, elle, est confirmée par le webhook reçu sur votre serveur.
// 1) Votre BACKEND crée le paiement et renvoie payment_url à l'app.
// 2) L'app ouvre la page de paiement (Chrome Custom Tabs) :
val intent = CustomTabsIntent.Builder().build()
intent.launchUrl(context, Uri.parse(paymentUrl))
// 3) Le client revient via votre deep link (return_url, ex: monapp://retour).
// La commande est confirmée par le WEBHOOK reçu sur votre serveur.
import SafariServices
// payment_url provient de VOTRE backend (jamais la clé secrète dans l'app)
let vc = SFSafariViewController(url: URL(string: paymentUrl)!)
present(vc, animated: true)
// Récupérez le retour via un Universal Link (return_url).
// La commande est validée par le WEBHOOK côté serveur.
Vérifier le statut d'un paiement
À tout moment, interrogez l'état d'un paiement avec son token (utile en complément du webhook, par exemple depuis votre page de retour).
GET /api/v1/payments/{token}/status
curl -H "TCHIN-PUBLIC-KEY: votre_cle_publique" \
-H "TCHIN-PRIVATE-KEY: votre_cle_privee" \
https://tchin.tech/api/v1/payments/ab12cd34ef/status
Le champ status vaut pending, completed, failed ou cancelled.
Mode test
Avec "env": "test", utilisez le compte de test de votre tableau de bord (menu API → « Compte test ») : email, numéro et mot de passe fictifs. Le paiement est simulé, aucun argent réel n'est déplacé et votre solde n'est pas crédité. Tchin envoie tout de même un webhook de test (mode: test) pour que vous puissiez valider votre intégration avant la production.
Questions fréquentes
Un même lien peut-il être payé plusieurs fois ?
Chaque appel à /payments crée un paiement à usage unique. Pour plusieurs ventes, créez un paiement par commande.
Combien Tchin prélève-t-il ?
Une commission de 5% est retenue à l'encaissement ; le reste (net) est crédité sur votre solde du pays concerné.
Que se passe-t-il si le client abandonne ?
Aucun webhook « completed » n'est envoyé ; ne validez pas la commande. Le client peut réessayer.