MobupayMobupay
Chargement de vos clés API…

Créer un paiement direct

POSThttps://api.mobupay.nc/api/v1/payments/direct

Ce que fait cet appel

Débite directement une carte tokenisée d'un client, sans page de paiement. Le client doit avoir un wallet et un paymentMethod actif.

Client présent : transmettez `browser`. L'empreinte du navigateur de votre client, adresse IP comprise. Mobupay l'authentifie (3D Secure) et demande l'exemption quand votre réglage l'accorde. Si sa banque ne demande rien, le débit est conclu dans la réponse (201 ou 402). Si elle exige un défi, la réponse est 202, status: "requires_action" : affichez nextAction.url dans un cadre de votre page, ou redirigez-y votre client ; la page Mobupay mène le défi puis débite, et le webhook payment.authorized ou payment.failed vous donne l'issue. Si l'authentification ne peut pas être menée (incident de l'acquéreur), le débit part sans elle, comme sans browser, et ne bénéficie pas du transfert de responsabilité. Sans browser, un débit initiator: customer part SANS authentification ni demande d'exemption, et beaucoup de banques le refusent 01131 (authentification exigée). Guide « Cartes enregistrées », étape 6 (/docs/guides/saved-cards#client-present).

Précisez `initiator` : si vous prélevez sans que le porteur soit devant l'écran, échéance d'abonnement ou solde de fin de mois, envoyez initiator: merchant. Le débit est alors déclaré comme initié par le marchand (UNSCHEDULED, rattaché à l'enregistrement de la carte), ce qu'attendent les réseaux. Il part sans authentification et ne bénéficie pas du transfert de responsabilité. Enregistrez la carte avec usage: "unscheduled" pour que son enregistrement déclare ces prélèvements.

En captureMode: "AUTO" (défaut), la capture est acquise dès cet appel : la réponse rend status: "captured" et capturedAt, sans qu'aucune scrutation ne soit nécessaire. Les webhooks payment.authorized et payment.captured sont émis dans la foulée, puis payment.settled au règlement, quand la commission devient définitive.

Pour les scénarios plateforme et le financement plateforme, voir la section Cas d'usage (/docs/usecases/distant).

Si vous exploitez plusieurs boutiques sur un même compte, storeId rattache l'encaissement à l'une d'elles : guide « Plusieurs boutiques » (/docs/guides/boutiques).

En-tête d'authentification
Authorization: Bearer sk_test_XXXX

Le pool est déduit du préfixe de la clé

Il n'y a pas d'interrupteur test et production sur cette page. sk_test_* ne traite aucun paiement réel, sk_live_* encaisse.

Corps de la requête

application/json
storeIdstringOptionnel

Boutique à laquelle rattacher cet encaissement. Accepte l'identifiant (`sto_*`) **ou le code** de la boutique, celui que vos propres systèmes connaissent déjà. **Champ de premier niveau** : à côté de `externalId`, jamais à l'intérieur de `order`. Une clé inconnue placée dans `order` est écartée en silence, et le paiement partirait alors sur le contrat par défaut sans qu'aucune erreur ne vous prévienne. Facultatif. Si votre clé API est déjà rattachée à une boutique, elle fait autorité et vous n'avez rien à transmettre : le corps peut la répéter, jamais la contredire (`STORE_KEY_MISMATCH`). Une boutique inconnue (`UNKNOWN_STORE`), désactivée (`STORE_INACTIVE`) ou déclarée point de vente physique (`STORE_KIND_MISMATCH`) fait échouer l'appel : elle n'est jamais ignorée. Vos boutiques se créent depuis votre espace marchand, Paramètres puis « Mes offres ». Voir le guide « Plusieurs boutiques » (/docs/guides/boutiques).

merchantConfigIdstringOptionnel

**Usage avancé.** Contrat d'encaissement à employer (`mcf_*`), désigné directement. Ce champ reste accepté, mais la voie normale est la boutique : `storeId`, ou une clé API rattachée à une boutique, désigne le contrat sans que vous ayez à le nommer. Facultatif : absent, le contrat actif par défaut s'applique. Si l'appel et la boutique désignent deux contrats différents, l'appel est refusé (`STORE_CONTRACT_CONFLICT`) : Mobupay n'arbitre jamais en silence entre deux contrats, puisque le choix décide du libellé porté au relevé du client et de la ventilation des fonds.

objectRequis

Détail de la commande à payer. Voir sous-objets `items`, `taxDetail`, `platformConfig`, `delivery`.

initiatorstringOptionnel

Qui déclenche ce prélèvement. `customer` (défaut) : le porteur est devant l'écran et l'a demandé ; transmettez alors `browser` pour qu'il soit authentifié, sans quoi le débit part sans 3D Secure et sa banque peut le refuser `01131`. `merchant` : vous prélevez sans lui, depuis une tâche de fond : une échéance d'abonnement, un solde de fin de mois. Le débit part alors en transaction initiée par le marchand et cite la transaction qui a enrôlé la carte. Déclarer `customer` pour un débit que le porteur n'a pas demandé est une déclaration inexacte, et elle se paie sur les taux d'acceptation. **Pas de transfert de responsabilité** : un prélèvement à l'initiative du marchand part sans authentification, rattaché à l'enregistrement de la carte (`UNSCHEDULED`) ; le risque de contestation reste chez vous. Une carte enrôlée avant septembre 2026 n'en a pas : le prélèvement aboutit, mais le risque de contestation reste chez vous.

captureModestringOptionnel

AUTO (défaut) = autorisation et capture dans le même appel : la réponse rend directement `status: "captured"` avec `capturedAt` renseigné, et vous recevez `payment.authorized` puis `payment.captured`. MANUAL = autorisation seule : `status: "authorized"`, `capturedAt` nul, capture à demander via `POST /payments/{id}/capture`. En MANUAL, l'autorisation a une durée de validité limitée (moins de 7 jours côté réseau carte) : sans capture dans ce délai, le client n'est jamais débité.

objectRequis

Identifie la carte tokenisée à débiter.

externalIdstringOptionnel

Identifiant externe du paiement côté marchand (sert d'idempotence sur les doublons). Max 255 caractères.

isInclTaxAmountbooleanOptionnel

Drapeau de la COMMANDE : ses prix (`items[].unitPrice`) et `order.amount` sont taxes comprises (`true`, défaut), et la taxe en est extraite ; ou hors taxes (`false`), et la taxe est calculée en plus des prix et portée dans `order.taxAmount`, sans être ajoutée au montant débité, qui reste `order.amount` (plus le pourboire). Une commission ne lit pas ce champ : ses taxes (`taxDetail`) s'ajoutent toujours à son montant.

languageCodestringOptionnel

Code langue (2 a 5 caractères). Défaut `fr`.

notificationUrlstringOptionnel

URL HTTPS de votre webhook (optionnel) : Mobupay y envoie (POST signé) `payment.authorized`, puis `payment.captured` si `captureMode` valait AUTO. Livrée en complément des endpoints webhook enregistrés. Si absent et aucun endpoint enregistré, seule la réponse HTTP indique le résultat (201 succès, 402 refus).

privateDataobjectOptionnel

Données privees libres conservées côté Mobupay.

objectOptionnel

Client présent : l'empreinte de son navigateur, relevée dans votre page. Avec elle, Mobupay authentifie le porteur et demande l'exemption ; sans elle, le débit part sans 3D Secure. Réservé à un client présent (`initiator: customer`, `intention` absente ou `one_click`), sinon 400 `BROWSER_REQUIRES_CUSTOMER_PRESENT`.

returnUrlstringOptionnel

Avec `browser`, facultatif : adresse HTTPS où la page d'authentification renvoie votre client, avec `paymentId` et `status`, quand elle n'est pas affichée dans un cadre.

Codes de retour

201

Paiement créé et exécuté. store restitue la boutique retenue (null si l'encaissement n'en porte aucune). En environnement de test, storeContractIgnored: true signale que le contrat rattaché à la boutique n'a pas été employé : ce pool n'en compte qu'un seul.

202

Client présent (browser) : la banque exige une étape d'authentification. Le paiement est en attente, status: "requires_action". Affichez nextAction.url dans un cadre de votre page (au moins 390 x 600 pixels) ou redirigez-y votre client, avant nextAction.expiresAt ; passé ce délai, le paiement expire (payment.expired). La page mène l'authentification, débite, puis envoie au cadre parent { mobupayPayment: { paymentId, status } }. Ce message sert à fermer le cadre : l'issue qui fait foi est le webhook (payment.authorized ou payment.failed) ou GET /api/v1/payments/{id}. Un rejeu avec la même Idempotency-Key rend un nouveau nextAction.url, l'ancien cessant de valoir.

400

Paramètres invalides. Sur la boutique : UNKNOWN_STORE (aucune boutique ne porte cet identifiant ni ce code), STORE_INACTIVE (boutique désactivée), STORE_KIND_MISMATCH (point de vente physique, il n'encaisse pas à distance), STORE_CONTRACT_INACTIVE (le contrat rattaché à la boutique n'est plus actif), STORE_CONTRACT_CONFLICT (l'appel et la boutique désignent deux contrats différents), STORE_KEY_MISMATCH (la clé API est rattachée à une autre boutique que celle demandée).

402

Paiement refusé par l'acquéreur (provision insuffisante, opposition, etc.). La ressource paiement est bien créée (traçabilité) : le corps est identique au 201 avec status: "failed", failureCode et failureReason. Ne vous fiez jamais au seul corps de réponse : un code HTTP 402 signifie qu'aucun fonds n'a été encaissé.

nextAction indique la conduite à tenir quand Mobupay en recommande une ; null ne veut PAS dire qu'aucune action n'est possible, seulement qu'aucune n'est recommandée pour ce code : reportez-vous alors à la colonne « Nouvelle tentative » des codes de refus (/docs/decline-codes). Sur un refus 01131 (authentification exigée), il vaut { "type": "checkout_session", "reason": "authentication_required", "documentation": "/docs/guides/saved-cards#client-present" } : créez une session de paiement avec le customerId, ou rejouez le débit avec browser si votre client est toujours sur votre page. Avec browser, un refus d'exemption est déjà relancé une fois par Mobupay, sans exemption. Ne bloquez pas la carte, ce refus est décidé paiement par paiement.

404

Customer ou paymentMethod introuvable.

422

L'acquéreur a REFUSÉ la requête (code ACQUIRER_REQUEST_REJECTED). Ce n'est pas un refus de la carte, et ce n'est pas une panne : rejouer le même appel ne peut pas aboutir. details.acquirerCode porte le code de refus de l'acquéreur et details.reason son libellé, de quoi corriger la demande avant de la renvoyer. Auparavant ce cas rendait 502, ce qui invitait au rejeu.

Langage

Requête cURLpostExemple
1curl --request POST \
2 --url https://api.mobupay.nc/api/v1/payments/direct \
3 --header 'authorization: Bearer sk_test_XXXX' \
4 --header 'content-type: application/json' \
5 --data '{ "order": { "reference": "SUB-2026-05", "amount": 2000, "currency": "XPF" }, "paymentInstrument": { "customerId": "cus_2KmBz9aQp4nT8R", "paymentMethodRank": 1 }, "captureMode": "AUTO", "externalId": "INV-2026-05-001", "storeId": "PAITA" }'
Réponse

Cliquez sur Essayer pour lancer la requête et voir la réponse ici. Ou choisissez un exemple :

application/json