Accueil / Développeurs
Documentation d'intégration marchand

API d'encaissement et de décaissement, intégrée en quelques étapes

Interface HTTP + JSON unifiée, signature et vérification SHA-256, notifications asynchrones et consultation active des commandes. Ce document couvre les règles de signature, l'ensemble des champs d'API et des exemples de requêtes.

Présentation

India Payme met à la disposition des marchands deux capacités de transaction essentielles : l'encaissement (Payin) — encaisser pour le compte du marchand auprès de l'utilisateur final ; le décaissement (Payout) — verser un paiement pour le compte du marchand vers un compte désigné. Toutes les API externes sont en POST + JSON, et doivent impérativement porter une signature d'API. Une fois le traitement terminé, la plateforme notifie le marchand via une notification asynchrone, et prend également en charge la consultation active des commandes.

FonctionMéthodeChemin
Créer un encaissementPOST/transaction/payin/v1/apply
Consulter un encaissementPOST/transaction/payin/v1/query
Créer un décaissementPOST/transaction/payout/v1/apply
Consulter un décaissementPOST/transaction/payout/v1/query
Consulter le soldePOST/transaction/payout/v1/balance

URL de base (le domaine de la passerelle de production vous sera communiqué par la plateforme après l'ouverture de votre compte) :

https://{domaine-passerelle}

Préparation à l'intégration

Connectez-vous à votre espace marchand → Clés d'application ; chaque application dispose d'une paire d'identifiants : appKey et appSecret. appKey correspond à l'en-tête de requête appId ; appSecret est la clé de signature, utilisée uniquement pour le calcul local de la signature — elle ne doit jamais être transmise.

Toutes les requêtes doivent inclure les en-têtes HTTP suivants, avec Content-Type défini sur application/json :

En-têteObligatoireDescription
appIdOuiID d'application du marchand (correspond à appKey)
timestampOuiHorodatage Unix en millisecondes
nonceOuiChaîne aléatoire, ≥ 10 caractères, à usage unique (non réutilisable)
signOuiSignature calculée selon les règles de la section suivante

Règles de signature

L'algorithme de signature est un SHA-256 pur (hexadécimal minuscule), et non un HMAC. L'appSecret est concaténé directement à la fin de la chaîne à signer, puis l'ensemble est passé au SHA-256. Étapes :

  1. Prenez « les champs de premier niveau du corps de la requête (uniquement les valeurs non vides) » + « les en-têtes de signature appId, timestamp, nonce », et fusionnez-les en une seule Map (sign lui-même n'y participe pas) ;
  2. Triez par nom de paramètre en ordre ASCII croissant, puis assemblez la chaîne sous la forme key1=value1&key2=value2… ;
  3. Concaténez directement appSecret à la fin (sans séparateur), puis calculez le SHA-256 de la chaîne complète en hexadécimal minuscule pour obtenir sign.
# Chaîne à signer signString = "key1=value1&key2=value2…&keyN=valueN" + appSecret sign = SHA256_HEX(signString) // hexadécimal minuscule

Validité et protection contre le rejeu :

  • Validité de l'horodatage : 30 secondes : |heure du serveur − timestamp| ≤ 30s, au-delà la réponse renvoyée est timestamp has expired. Assurez-vous que l'horloge de votre client et celle de la passerelle sont synchronisées (NTP).
  • Protection anti-rejeu via nonce : un même nonce ne peut être utilisé qu'une seule fois ; en cas de réutilisation, l'erreur nonce has been used est renvoyée (code d'erreur 900).
  • Les champs à valeur vide ne participent pas à la signature — « l'ensemble des champs inclus dans la signature » doit correspondre exactement « aux champs JSON réellement envoyés ».

Exemple de signature en Node.js :

const crypto = require('crypto'); function buildSign(appId, appSecret, timestamp, nonce, body) { const params = { ...body, appId, timestamp, nonce }; const signString = Object.keys(params) .filter(k => params[k] !== null && params[k] !== undefined) .sort() .map(k => `${k}=${params[k]}`) .join('&') + appSecret; return crypto.createHash('sha256').update(signString, 'utf8').digest('hex'); }

Créer un encaissement POST

POST /transaction/payin/v1/apply — crée une commande d'encaissement et renvoie le lien de paiement de la caisse payUrl, permettant de rediriger l'utilisateur pour finaliser le paiement.

ChampTypeObligatoireDescription
merchantOrderNostringOuiNuméro de commande du marchand, ne doit pas être réutilisé
amountnumberOuiMontant de la commande, décimal (ex. 100.02)
namestringOuiNom de l'utilisateur. Uniquement en lettres, ≥ 3 caractères, espaces autorisés, sans symboles ni chiffres
phonestringOuiNuméro de téléphone
emailstringOuiAdresse e-mail
currencystringOuiDevise : INR / PKR / USDT / BDT
productstringOuiCode produit de paiement, fourni par la plateforme selon votre contrat
notifyUrlstringNonAdresse de notification asynchrone ; à défaut, l'adresse par défaut du marchand est utilisée
returnUrlstringNonPage de redirection après paiement réussi
payTypestringNonMode de paiement direct par portefeuille : JAZZCASH / EASYPAISA / BKASH / NAGAD
POST /transaction/payin/v1/apply { "merchantOrderNo": "ORD1751731200123", "amount": "600.00", "currency": "INR", "product": "{code-produit}", "name": "John Doe", "phone": "9910099100", "email": "john@example.com", "notifyUrl": "https://shop.example/pay/notify" }
// Réponse { "code": 0, "msg": "Success", "data": { "orderNo": "P1751731200999", "merchantOrderNo": "ORD1751731200123", "amount": 600, "currency": "INR", "payUrl": "https://{domaine-caisse}/cashier/xxxx", "payStatus": 0 } }

Une fois le payUrl obtenu, redirigez l'utilisateur pour effectuer le paiement ; le résultat final fait foi via la notification asynchrone.

Créer un décaissement POST

POST /transaction/payout/v1/apply — initie un versement vers un compte désigné. Traitement asynchrone : l'API procède d'abord à la vérification et au blocage du compte, puis met en correspondance de façon asynchrone le canal de décaissement ; la réponse renvoie en général payStatus=0 (demande acceptée), le statut final faisant foi via consultation ou notification.

ChampTypeObligatoireDescription
merchantOrderNostringOuiNuméro de commande du marchand
amountnumberOuiMontant du versement, minimum 100,00
accountNamestringOuiNom du bénéficiaire. Uniquement en lettres, ≥ 3 caractères, espaces autorisés
accountstringOuiNuméro de compte du bénéficiaire
phonestringOuiNuméro de téléphone
emailstringOuiAdresse e-mail
currencystringOuiDevise : INR / PKR / USDT / BDT
bizCodestringOuiType de canal de décaissement : IMPS / UPI / BANK / JAZZCASH / EASYPAISA / BKASH / NAGAD / ECARD
payCodestringOuiMode de paiement : CARD / WALLET / NBK / ITT / VC
branchCodestringOuiCode de compensation : IFSC pour l'Inde ; bankcode pour le Pakistan ; selon le bizCode pour le Bangladesh
productstringOuiCode produit de paiement, fourni par la plateforme
bankNamestringNonNom de la banque
swiftCodestringNonCode SWIFT (utilisé pour les virements transfrontaliers ITT)
POST /transaction/payout/v1/apply { "merchantOrderNo": "PO1751731200123", "amount": "1500.00", "currency": "INR", "product": "{code-produit}", "accountName": "John Doe", "account": "1234567890", "bizCode": "IMPS", "payCode": "NBK", "branchCode": "HDFC0000001", "bankName": "HDFC", "phone": "9910099100", "email": "john@example.com" }

Consultation de commande POST

Encaissement : POST /transaction/payin/v1/query ; décaissement : POST /transaction/payout/v1/query. Transmettez merchantOrderNo ou orderNo pour localiser la commande. Limité à 5 requêtes/seconde.

POST /transaction/payin/v1/query { "merchantOrderNo": "ORD1751731200123" }
// data renvoyé { "orderNo": "P1751731200999", "merchantOrderNo": "ORD1751731200123", "amount": 600, "realAmount": 600, "currency": "INR", "payStatus": 1 // 0 en cours de traitement / 1 encaissé / -1 annulé }

Consultation de solde POST

POST /transaction/payout/v1/balance — consulte le solde du compte marchand. Limité à 5 requêtes/seconde.

POST /transaction/payout/v1/balance { "currency": "INR" }
// data renvoyé { "accountNo": "ACC0001", "currency": "INR", "balance": 100000.00, // Solde total "balanceActive": 98500.00, // Solde disponible "balanceFreeze": 1500.00 // Solde bloqué }

Notification asynchrone

Lorsqu'une commande atteint un statut final, la plateforme notifie le marchand via POST (JSON) à l'adresse notifyUrl (ou à l'adresse par défaut du marchand si non transmise), en incluant les mêmes en-têtes de signature (appId/timestamp/nonce/sign). Le marchand doit recalculer la signature avec son propre appSecret selon les mêmes règles et la comparer, afin de vérifier l'authenticité de la notification.

Le message de notification d'encaissement comprend : merchantOrderNo, orderNo, currency, product, amount, realAmount, status (encaissement réussi : "1"). La notification de décaissement inclut en outre utr (numéro de référence bancaire) et statusDes (description du statut), status valant "1" pour succès / "2" pour échec.

// Exemple de body de notification d'encaissement { "merchantOrderNo": "ORD1751731200123", "orderNo": "P1751731200999", "currency": "INR", "product": "{code-produit}", "amount": "600.00", "realAmount": "600.00", "status": "1" }

Le marchand doit renvoyer le texte brut OK ou success (insensible à la casse). Dans le cas contraire, la plateforme place la notification dans une file de nouvelles tentatives : 5 essais maximum, avec un intervalle croissant en minutes (1 / 2 / 5 / 10 / 30 / 60 / 120). L'interface du marchand doit donc être idempotente (un même orderNo peut être notifié plusieurs fois).

Statut de commande

L'intégration du marchand doit se baser sur les statuts publics ci-dessous (la machine à états interne est plus détaillée et n'est pas exposée directement) :

ScénarioChampValeurs
Réponse à la création de commandepayStatus0 créée / 1 réussie / 2 échouée / 3 annulée
Consultation d'encaissementpayStatus0 en cours de traitement / 1 encaissé / -1 annulé
Consultation de décaissementpayStatus0 en attente de paiement / 1 payé / -1 annulé
Notification asynchronestatusEncaissement réussi "1" ; décaissement "1" réussi / "2" échoué

Codes d'erreur

Un corps de réponse avec code != 0 indique un échec, msg fournit le message associé. Codes d'erreur métier courants :

codeDescription
0Succès
400Paramètre invalide / échec de vérification de signature (Sign invalid)
900Requête dupliquée / rejeu de nonce
10000 / 10001Application introuvable / application indisponible
10002Devise non prise en charge
10003 / 10007Marchand indisponible / compte marchand indisponible
10004Produit non activé ou contrat expiré
10005 / 10009Aucun canal disponible / canal temporairement indisponible
10008Solde du compte insuffisant
10010Adresse IP hors liste blanche
10011 / 10012Produit invalide / mode de paiement invalide
10020Numéro de commande marchand en doublon
30001 / 30002Numéro de commande erroné / devise erronée ou compte non activé

Parcours d'intégration complet

Exemple avec un encaissement :

  1. Construisez le corps de la requête métier (voir les champs de « Créer un encaissement »).
  2. Générez timestamp (en millisecondes) et nonce (chaîne aléatoire ≥ 10 caractères).
  3. Calculez sign selon les « Règles de signature ».
  4. Envoyez la requête POST /transaction/payin/v1/apply avec les 4 en-têtes de signature et le corps JSON.
  5. Si code==0, récupérez data.payUrl pour rediriger l'utilisateur vers le paiement.
  6. Écoutez la notification asynchrone ; vous pouvez également consulter activement la commande pour vérifier le statut final.
  7. Après réception de la notification, vérifiez la signature, traitez la logique métier, puis renvoyez le texte brut OK.

Remarque : les chemins d'API, champs et codes de statut de ce document correspondent à l'implémentation de production ; le domaine de la passerelle de production, les codes produit product disponibles et la politique de liste blanche IP vous seront communiqués par la plateforme après l'ouverture de votre compte.

Obtenez vos clés et commencez à développer

Ouvrez un compte en ligne pour obtenir vos identifiants de test et vos codes produit ; une fois validé en bac à sable, basculez en production en un clic.