Aller au contenu principal
Tous les articles
Technique14 min de lecture

Tester un paiement en ligne en mode test : carte de test, scénarios et limites de la sandbox

Tester un paiement en ligne sans argent réel : la carte de test, le code 3-D Secure, un plan de recette par scénarios et ce que la sandbox ne couvre pas.

Pour tester un paiement en ligne sans argent réel, créez une clé chari_sk_test_…, appelez la même API qu'en production et payez avec la carte de test 4918 9141 0719 5005, le CVV 123, n'importe quelle date d'expiration future et le code 3-D Secure 555. Le parcours est complet — page de paiement hébergée, authentification, webhook signé, remboursement, export — mais aucun dirham ne circule. Ce guide donne la carte et le code, ce que la sandbox couvre module par module, un plan de recette en six scénarios à dérouler avant tout lancement, et ce qui ne se teste pas, avec la façon de le vérifier autrement.

Le mode test : la même API, une clé de test

ChariPay est une plateforme de paiement marocaine, un PSP opéré par Chari Money, établissement de paiement agréé par Bank Al-Maghrib. Son mode test n'est pas une maquette : c'est la même API, sur la même base https://api-psp.charipay.ma, avec les mêmes chemins, les mêmes payloads et les mêmes codes d'erreur qu'en production. Ce qui change, c'est la clé. Une clé qui commence par chari_sk_test_ travaille en sandbox, une clé chari_sk_live_ en production : vous ne choisissez l'environnement ni dans l'URL ni dans un en-tête, vous le choisissez en choisissant la clé. Les deux environnements sont isolés : un même externalId peut exister une fois dans chacun.

Le mode test s'ouvre dès l'activation de votre compte, sans validation à attendre : Commencer en mode test. Trois champs — nom, e-mail professionnel, entreprise —, un lien d'activation reçu par e-mail pour choisir votre mot de passe, puis le portail, où vous créez vous-même votre clé de test après une ré-authentification. La clé complète ne s'affiche qu'une seule fois et n'est jamais envoyée par e-mail : rangez-la aussitôt dans une variable d'environnement ou un coffre, jamais dans le dépôt. La vérification de votre entreprise (KYB) se fait en parallèle et ne conditionne que le passage en production.

Le mode test est gratuit, sans limite de durée et sans engagement ; la page tarification détaille ce qui ne s'applique qu'au passage en production. Pour les conventions communes à tous les appels — authentification, pagination, idempotence, erreurs —, l'espace développeurs et la documentation de l'API font référence.

La carte de test et le code 3-D Secure

Voici la carte à saisir sur la page de paiement, comme le ferait un client ; elle déclenche le parcours réel — page de paiement, authentification 3-D Secure, webhook.

ChampValeur à saisir
Numéro de carte4918 9141 0719 5005
CVV123
Date d'expirationn'importe quelle date future
Code 3-D Secure555

Seule cette carte est acceptée, et aucun argent réel ne circule. Toute autre carte — la vôtre, celle d'un collègue ou un numéro de test copié d'une autre plateforme — est rejetée avec un 502 et le code BAAS_CHARI_ERROR. Si vous voyez cette réponse pendant vos tests, vérifiez la carte saisie avant de chercher un bug dans votre code ; les autres réponses d'erreur sont expliquées une à une dans codes d'erreur de l'API de paiement.

Aucune carte « de refus » n'est publiée : la sandbox n'en accepte qu'une, celle-ci. Les échecs se provoquent donc par le parcours lui-même — abandon, expiration, requête mal formée —, comme le montre le plan de recette plus bas. L'étape que vous traversez avec le code 555 est celle que vos clients traverseront avec leur banque. Les paiements par carte passent par l'authentification 3-D Secure : le porteur confirme auprès de sa banque, ce qui protège le commerçant contre l'essentiel des impayés et des contestations. Ce que cette étape change sur vos ventes réelles est détaillé dans 3-D Secure et taux de réussite.

Ce que couvre la sandbox de paiement, module par module

Six familles se testent de bout en bout avec une clé de test. Pour chacune, voici comment la déclencher et ce qu'il faut vérifier :

ModuleComment le déclencherCe que vous vérifiez
Liens de paiementPOST /v1/payment-links, ou depuis le portaille payUrl s'ouvre, la carte de test passe, le lien passe « Payé »
Sessions de checkoutPOST /v1/payment-sessions, puis redirection vers checkoutUrlretour sur accept, événement signé, statut lu par GET /v1/payment-sessions/{sessionId}
AbonnementsPOST /v1/clients, puis POST /v1/subscriptions en DAILY avec une startDate du jourpremier lien de paiement dans currentCharge, payé avec la carte de test, subscription.payment_succeeded, deuxième échéance le lendemain
RemboursementsPOST /v1/refunds, ou depuis le portail202 à la création, 200 au rejeu, refund.succeeded ou refund.failed
Webhooksendpoint déclaré avec la clé de testévénements envoyés normalement, signature vérifiée, journal des livraisons
Exportsportail, ou GET /v1/transactions/export.csvréférences présentes, horodatages en UTC

Cette liste est le périmètre promis de la sandbox. Les webhooks y partent comme en production, signés avec le secret de l'endpoint de sandbox : votre récepteur peut s'y tromper sans conséquence.

Tester un paiement en ligne de bout en bout, étape par étape

Commencez par le parcours d'une commande passée sur votre site : une session de paiement. Créez-la côté serveur, avec votre clé de test :

bash
curl -X POST 'https://api-psp.charipay.ma/v1/payment-sessions' \
  -H 'X-CHARI-PAY-API-KEY: chari_sk_test_...' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: order-2026-0421-session' \
  -d '{
    "amount": 250.00,
    "orderId": "ORD-2026-0421",
    "externalId": "order-2026-0421",
    "config": {
      "customer": {
        "email": "amine.bennani@example.com",
        "firstName": "Amine",
        "lastName": "Bennani",
        "phone": "+212600000000"
      },
      "urls": {
        "accept": "https://votre-boutique.ma/paiement/succes",
        "decline": "https://votre-boutique.ma/paiement/echec",
        "notification": "https://votre-boutique.ma/webhooks/charipay"
      }
    },
    "metadata": { "cartId": "c_987", "source": "web" }
  }'

La réponse — 201, ou 200 si vous rejouez le même externalId — contient ces cinq champs, et rien d'autre :

json
{
  "sessionId": "ps_5Kd0Rn",
  "sessionToken": "st_…",
  "verifyKey": "vk_5Kd0Rn",
  "expiresAt": "2026-10-05T10:15:00Z",
  "checkoutUrl": "https://…/checkout/ps_5Kd0Rn"
}

Le statut et le montant ne figurent pas dans cette réponse : ils se lisent par GET /v1/payment-sessions/{sessionId}. Déroulez ensuite le parcours comme votre client le vivra :

  1. 1Enregistrez le `sessionId` en face de votre commande, à l'état « en attente de paiement ».
  2. 2Ouvrez `checkoutUrl` tel que la réponse le donne, dans un navigateur, comme le ferait l'acheteur.
  3. 3Payez avec la carte de test, puis saisissez 555 à l'étape 3-D Secure.
  4. 4Revenez sur l'URL `accept` : votre page affiche un état d'attente, pas encore une confirmation.
  5. 5Recevez l'événement signé payment.succeeded sur votre endpoint de sandbox, vérifiez sa signature, et confirmez la commande à ce moment-là.
  6. 6Relisez le statut par GET /v1/payment-sessions/{sessionId} pour vérifier que votre base et la nôtre disent la même chose.

L'ordre des étapes 4 et 5 n'est pas garanti, et c'est précisément ce que le test doit montrer : confirmez la commande sur réception du webhook, jamais sur la seule redirection — la redirection dit que l'acheteur est revenu, pas que le paiement est acquis. Retenez aussi que l'URL notification, comme tout endpoint déclaré, doit être joignable en HTTPS public : sur un poste de développement, il faut un tunnel.

Variante sans session : le lien de paiement.

bash
curl -X POST 'https://api-psp.charipay.ma/v1/payment-links' \
  -H 'X-CHARI-PAY-API-KEY: chari_sk_test_...' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: order-1042-link' \
  -d '{
    "amount": 149.90,
    "description": "Commande #1042",
    "singleUse": true,
    "externalId": "order-1042",
    "customerEmail": "amine.bennani@example.com",
    "customerPhone": "+212600000000",
    "metadata": { "cartId": "c_987" }
  }'

La réponse donne la reference du lien (pl_…) et son payUrl : ouvrez le payUrl, payez avec la carte de test, puis lisez l'état du lien par GET /v1/payment-links/{reference}. Le guide API de paiement au Maroc replace ces deux appels dans l'intégration complète.

Un plan de recette en six scénarios

Un paiement réussi ne prouve pas grand-chose : ce sont les cas limites qui cassent une intégration le jour du lancement. Rejouez-les en sandbox, dans cet ordre.

ScénarioComment le provoquerRésultat attendu
1. Paiement réussisession, carte de test, code 555retour sur accept, payment.succeeded signé, commande confirmée à la réception de l'événement
2. Abandon pendant l'authentificationsaisir la carte, puis fermer l'onglet à l'étape 3-D Secureaucune confirmation, commande toujours « en attente », statut relu par GET /v1/payment-sessions/{sessionId}
3. Session expiréecréer une session avec un expiresAt à quelques minutes, attendre qu'il passela session ne se paie plus ; en checkout direct, POST /checkout/verify répond 410 SESSION_EXPIRED ; votre commande passe à l'état prévu
4. Double clicrejouer la création avec la même Idempotency-Key, puis avec le même externalIdle premier résultat revient ; 200 au lieu de 201 sur externalId ; aucune seconde session
5. Remboursementstotal sur un premier paiement ; partiel avec refundAmount sur un second ; rejeu de la même refundReference202 à la création, 200 au rejeu, refund.succeeded, aucun double débit
6. Événement de testdepuis le portail ou l'API, sur l'endpoint de sandboxsignature acceptée, réponse 2xx rapide, aucun effet métier

Quelques règles rendent ce plan fiable. Le remboursement partiel se teste sur un autre paiement que le remboursement total, et chaque remboursement désigne son paiement par l'operationId lu dans GET /v1/transactions. Sur le scénario 4, rejouez aussi la même Idempotency-Key avec un corps modifié, y compris un nouvel externalId : la réponse attendue est 409 IDEMPOTENCY_CONFLICT, et elle doit être traitée comme une erreur de votre code, pas comme un incident réseau. Si l'externalId reste le même, c'est la session existante qui revient, en 200. Le mécanisme complet est expliqué dans l'idempotence des paiements.

N'écrivez aucun flux métier qui dépende de payment.failed : cet événement n'est envoyé que si vous l'avez demandé à la création de la session (notifyOnFailure). Un échec se constate en lisant le statut, et une commande sans confirmation reste en attente jusqu'à l'expiration de sa session. Enfin, le scénario 6 se déroule en détail dans tester ses webhooks en local : tunnel HTTPS, événement de test, journal des livraisons.

Abonnements, webhooks et exports : les vérifications oubliées

Abonnements. Un abonnement ChariPay est une suite de liens de paiement, un par échéance, envoyés par e-mail au client : il se teste en raccourcissant le calendrier. Créez le client (POST /v1/clients) puis l'abonnement (POST /v1/subscriptions) avec une startDate du jour et la périodicité DAILY : le premier lien est créé immédiatement et renvoyé dans currentCharge, et l'abonnement reste INCOMPLETE jusqu'à son paiement. Payez ce lien avec la carte de test, sur la page hébergée avec 3-D Secure : l'abonnement passe ACTIVE et vous recevez subscription.payment_succeeded. Le lendemain, une deuxième échéance s'ouvre avec un nouveau lien, à payer de la même façon. Les champs, les événements et le plan de recette complet sont détaillés dans intégrer les abonnements par l'API.

Webhooks. Déclarez un endpoint avec votre clé de test : il appartient à l'environnement de cette clé et reçoit son propre secret de signature (whsec_…), distinct de celui de production. Votre code doit lire ce secret dans la configuration de l'environnement, jamais en dur, sinon, après la bascule en production, votre vérification rejettera chaque notification.

Exports. Exportez les transactions de votre recette — depuis le portail ou par GET /v1/transactions/export.csv — et vérifiez deux choses. Chaque mouvement porte la référence de la vente, du remboursement ou du versement qui l'explique, et un remboursement apparaît comme un mouvement distinct lié à la transaction d'origine. Les horodatages sont en UTC ; le Maroc est en UTC+1 : votre outil de rapprochement doit convertir, faute de quoi un paiement passé juste après minuit tombe sur la veille.

Ce qui ne se teste pas, et comment le vérifier autrement

La sandbox ne promet pas tout. Trois choses restent hors de son périmètre :

  • Un dépôt d'espèces réel en agence. Créez le lien à usage unique avec paymentMethod: "CASH" et vérifiez que votre code sait lire son état. En production, dès que le réseau confirme le dépôt, le lien passe « Payé » et vous êtes notifié dans le portail ; côté serveur, l'état du lien se lit par GET /v1/payment-links/{reference}. Le dépôt lui-même ne se joue pas en sandbox.
  • Un virement bancaire ou un paiement de facture réels. Le parcours de virement du portail se déroule — en sandbox, n'importe quel code à six chiffres valide l'envoi —, mais aucun bénéficiaire ni aucun créancier ne reçoit quoi que ce soit.
  • Une carte autre que la carte de test. Elle reçoit 502 BAAS_CHARI_ERROR. Le comportement d'une vraie carte — authentification auprès de la banque émettrice, ouverture au paiement en ligne — ne s'observe qu'en production.

Ces trois parcours se vérifient sur de vraies opérations, une fois votre compte activé : dans le portail et dans l'export. La sandbox, elle, ne disparaît pas après le lancement : elle reste votre environnement de recette. Gardez deux jeux de variables d'environnement et testez chaque évolution en sandbox avant de la livrer. Au passage en production, vous ne changez que la clé et le secret de webhook : les URL, les payloads et les codes d'erreur sont identiques. Tant que la production n'est pas activée, une clé chari_sk_live_… reçoit 403 PRODUCTION_ACCESS_NOT_ENABLED. La liste de bascule du jour J est dans passer de la sandbox à la production.

Questions fréquentes

Quelle carte de test utiliser pour tester un paiement en ligne ?

La carte 4918 9141 0719 5005, avec le CVV 123, n'importe quelle date d'expiration future et le code 3-D Secure 555. C'est la seule carte acceptée en sandbox : elle déclenche le parcours complet — page de paiement, authentification, webhook signé — sans qu'aucun argent réel ne circule. Toute autre carte est rejetée avec un 502 et le code BAAS_CHARI_ERROR.

Quel code 3-D Secure saisir en mode test ?

Saisissez 555 à l'étape d'authentification, après avoir entré la carte de test. Cette étape reproduit celle que vos clients traversent en production avec leur banque : elle vérifie que votre parcours supporte la redirection vers l'authentification puis le retour sur votre URL accept. Aucun autre code n'est documenté pour la sandbox.

Peut-on tester un paiement avec sa vraie carte dans la sandbox ?

Non. En sandbox, seule la carte de test est acceptée : une carte réelle, quelle que soit sa banque, est rejetée avec un 502 et le code BAAS_CHARI_ERROR. Le comportement d'une vraie carte — authentification auprès de la banque émettrice, ouverture au paiement en ligne — ne s'observe qu'en production, une fois votre compte activé.

Faut-il attendre la validation de son entreprise pour utiliser le mode test ?

Non. Le mode test s'ouvre dès l'activation de votre compte, sans validation à attendre : vous créez votre clé de test depuis le portail et payez avec la carte de test. La vérification de votre entreprise (KYB) — documents d'identité et registre de commerce — se fait en parallèle et ne conditionne que le passage en production. Votre équipe technique peut donc bâtir et tester l'intégration pendant l'étude du dossier.

Comment simuler un paiement non abouti en mode test ?

Aucune carte « de refus » n'est publiée : l'échec se provoque par le parcours. Fermez l'onglet à l'étape 3-D Secure pour simuler un abandon, ou créez une session avec un expiresAt proche et laissez-la expirer. Vérifiez ensuite qu'aucune commande n'est confirmée — en attente après l'abandon, à l'état prévu après l'expiration — et lisez le statut par GET /v1/payment-sessions/{sessionId}. N'appuyez aucun traitement sur payment.failed, envoyé seulement si vous l'avez demandé.

Peut-on tester un paiement en espèces en agence dans la sandbox ?

Pas le dépôt lui-même : aucun dépôt d'espèces réel ne se fait en sandbox. Vous pouvez créer le lien à usage unique avec paymentMethod: "CASH" et vérifier que votre code lit son état par GET /v1/payment-links/{reference}. En production, dès que le réseau confirme le dépôt, le lien passe « Payé » et vous êtes notifié dans le portail.

Comment tester plusieurs échéances d'abonnement ?

Créez l'abonnement avec une startDate du jour et la périodicité DAILY, avec votre clé de sandbox. Le premier lien de paiement est créé immédiatement et renvoyé dans currentCharge : payez-le avec la carte de test, code 3-D Secure 555, et vous observez subscription.payment_succeeded sur votre endpoint. Le lendemain, une deuxième échéance s'ouvre, avec un nouveau lien : en trois jours, vous avez vu trois échéances. Le plan de recette complet figure dans le guide des abonnements par l'API.

Les webhooks sont-ils envoyés en mode test ?

Oui, normalement : paiements, remboursements et échéances de test déclenchent leurs événements signés vers l'endpoint déclaré avec votre clé de test. Cet endpoint appartient à la sandbox et a son propre secret, distinct de celui de production. Pour vérifier votre récepteur sans paiement, envoyez l'événement de test : un payment.succeeded synthétique portant Test: true, qui ne correspond à aucun paiement réel.

Prochaine étape

Créez votre compte et votre clé de test — Commencer en mode test —, puis déroulez les six scénarios de ce plan sur votre propre intégration, dans l'ordre, avec la carte de test. Le récepteur d'événements se règle ensuite avec tester ses webhooks en local, et la liste de bascule viendra en dernier, avec passer de la sandbox à la production.

Écrit par Équipe ChariPay.

À lire ensuite

Prêt à essayer par vous-même ?

Créez votre compte et encaissez en mode test dès aujourd'hui : c'est gratuit, sans validation à attendre. Une question ? Notre équipe répond aux commerçants comme aux développeurs.

  • Gratuit, sans engagement
  • Mode test dès l'inscription
  • Aucune validation à attendre