Tapaya
Acceptation des paiements en magasinGuide d’intégrationCloud Accept APIBeta

Cloud Accept API

Beta

Lancez des paiements en magasin sur un appareil Tapaya appairé depuis votre ECR ou votre backend POS.

La Cloud Accept API permet à votre caisse enregistreuse électronique (ECR) ou à votre backend POS de lancer un paiement sur un appareil Tapaya via le cloud. Votre système ne communique jamais directement avec l’appareil : il envoie une demande de paiement à Tapaya, Tapaya avertit l’appareil appairé, et l’appareil affiche l’écran de paiement au client. La progression vous parvient sous forme de webhooks, ou vous l’obtenez par interrogation régulière (polling).

Choisir comment appairer les appareils

Chaque appareil auquel vous envoyez des paiements a besoin d’un externalDeviceId : le nom que votre système lui donne, par exemple till-01. Attribuez-le de l’une des deux manières suivantes :

Avant de commencer

  1. Obtenez votre Server Secret Token sur la page API Keys. Vous l’échangez ci-dessous contre un jeton d’accès limité à un commerçant (voir l’authentification de la Platform API).
  2. Enregistrez le commerçant et conservez son merchantToken. Voir Enregistrer un nouveau commerçant.
  3. Préparez chaque appareil avec l’application Tapaya connectée pour ce commerçant, afin qu’il puisse être appairé et recevoir des demandes.

Un jeton, un commerçant

Chaque appel à la Cloud Accept API est limité à un seul et unique commerçant. Pour servir plusieurs commerçants, échangez un jeton d’accès distinct pour chacun d’eux.

Appairer un appareil

L’appairage attribue un externalDeviceId à un appareil Tapaya, afin que vous puissiez le retrouver lorsque vous listez les appareils et le cibler lorsque vous lancez un paiement.

Attribuer depuis votre application

Votre application appelle une fonction de l’Accept SDK sur l’appareil pour lui attribuer son externalDeviceId. Utilisez le même identifiant dans chaque appel à la Cloud Accept API concernant cet appareil.

Scanner un QR code

Le commerçant ouvre le parcours d’appairage dans la Tapaya Platform, qui affiche un QR code pour l’externalDeviceId à attribuer. Le commerçant le scanne avec l’application commerçant Tapaya sur l’appareil cible, et l’application finalise l’appairage.

Échanger un jeton d’accès

Échangez votre Server Secret Token et le merchantToken du commerçant contre un jeton d’accès avec POST /ecr/auth. Le merchantToken n’est envoyé qu’ici ; tous les appels suivants envoient uniquement Authorization: Bearer <accessToken>.

curl -X 'POST' 'https://api.tapaya.com/ecr/auth' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer REPLACE_ME' \
-d '{
        "merchantToken": "unique_merchant_id_from_your_db"
    }'
200 OK
{
    "accessToken": "...",
    "tokenType": "Bearer",
    "expiresAt": "2026-01-13T16:30:59Z"
}
CodeDescription
401Jeton API invalide ou expiré.
403L’accès au commerçant n’est pas autorisé.

Renouvelez le jeton avant expiresAt. Appelez POST /ecr/auth/refresh avec l’accessToken actuel, encore valide, dans l’en-tête Authorization. L’appel renvoie le même corps avec un nouveau jeton ; enregistrez-le et utilisez-le désormais.

curl -X 'POST' 'https://api.tapaya.com/ecr/auth/refresh' \
-H 'Authorization: Bearer ACCESS_TOKEN'
CodeDescription
401Le jeton d’accès est invalide, expiré ou révoqué. Échangez-en un nouveau avec POST /ecr/auth.
403Vous n’avez plus accès au commerçant. Aucun nouveau jeton n’est émis.

Trouver un appareil prêt

Listez les appareils du commerçant avec GET /ecr/devices. Ajoutez ?connected=true pour exclure les appareils déconnectés, ou récupérez un seul appareil avec GET /ecr/devices/{externalDeviceId}.

curl 'https://api.tapaya.com/ecr/devices/till-01' \
-H 'Authorization: Bearer ACCESS_TOKEN'
200 OK
{
    "externalDeviceId": "till-01",
    "name": "Front counter",
    "connected": true,
    "availability": "ready",
    "lastSeenAt": "2026-01-13T16:30:59Z",
    "updatedAt": "2026-01-13T16:30:59Z"
}

N’envoyez des paiements qu’à un appareil dont l’availability vaut ready. La liste n’est qu’un instantané : la disponibilité est vérifiée de nouveau lors de l’envoi, si bien qu’un appareil ready peut tout de même refuser une demande. Voir Disponibilité des appareils.

Envoyer une demande de paiement

Envoyez le montant à un appareil avec POST /ecr/payment-requests. Tapaya enregistre la demande et avertit l’appareil, qui affiche l’écran de paiement.

curl -X 'POST' 'https://api.tapaya.com/ecr/payment-requests' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Idempotency-Key: order-1042-attempt-1' \
-d '{
        "externalDeviceId": "till-01",
        "amount": 12500,
        "tipAmount": 500,
        "currency": "CZK"
    }'

Paramètres :

ChampTypeObligatoireDescription
externalDeviceIdstring✓L’appareil appairé qui doit afficher le paiement.
amountinteger✓Montant dans la plus petite unité de la devise (12500 correspond à 125,00 Kč).
tipAmountintegerPourboire dans la plus petite unité de la devise.
currencystring✓Code de devise ISO 4217.
paymentTokenstringUn paiement existant auquel rattacher la demande.
202 Accepted
{
    "requestId": "...",
    "status": "pending",
    "paymentToken": null,
    "expiresAt": "2026-01-13T16:30:59Z"
}

202 n’est pas un résultat de paiement

202 Accepted signifie que Tapaya a enregistré la demande. Cela ne signifie pas que l’appareil l’a vue ni que le client a payé. Tout ce qui échoue ensuite vous parvient sous forme de changement de statut.

Sécurisez les nouvelles tentatives. L’en-tête Idempotency-Key est obligatoire. Réutiliser une clé avec le même corps renvoie la demande d’origine au lieu de lancer un second paiement ; la réutiliser avec un corps différent renvoie 409 idempotency_conflict. Associez la clé à la vente et à la tentative, comme dans order-1042-attempt-1.

Suivre le résultat

Suivez la demande à travers ses statuts avec des webhooks, ou interrogez régulièrement GET /ecr/payment-requests/{requestId}. Dès qu’elle atteint payment_created, la réponse contient le paymentToken, et les événements payment.updated rendent compte de la progression du paiement lui-même.

Pour recevoir des webhooks, enregistrez votre endpoint HTTPS avec POST /ecr/webhook-subscriptions, ou définissez l’URL de callback et les types d’événements du commerçant dans la Tapaya Platform.

curl -X 'POST' 'https://api.tapaya.com/ecr/webhook-subscriptions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-d '{
        "url": "https://integrator.example.com/webhooks/tapaya",
        "events": ["payment_request.updated", "payment.updated"]
    }'
201 Created
{
    "subscriptionId": "...",
    "url": "https://integrator.example.com/webhooks/tapaya",
    "events": ["payment_request.updated", "payment.updated"],
    "signingSecret": "..."
}

Enregistrez le signing secret

signingSecret n’est renvoyé qu’à la création de l’abonnement. Conservez-le en lieu sûr ; vous en avez besoin pour vérifier la signature des webhooks entrants.

Un abonnement appartient à l’intégrateur et au commerçant, et non à un jeton d’accès ; il est donc conservé lors du renouvellement du jeton. Répondez à chaque événement par un 2xx dès que vous l’avez accepté.

Vérifiez avant de clôturer la vente

Les webhooks sont des notifications, et non une preuve de paiement ; un webhook peut arriver en retard, ou ne jamais arriver. Ne clôturez jamais une vente sur la seule base d’un webhook :

  • Lorsqu’un webhook arrive, confirmez le résultat final via l’API, par exemple avec Récupérer les détails d’un paiement.
  • Lorsqu’aucun webhook n’arrive dans un délai adapté à votre parcours d’encaissement, et au plus tard à l’expiresAt de la demande, appelez GET /ecr/payment-requests/{requestId} pour lire son statut actuel, puis confirmez le paiement via l’API comme ci-dessus.

Référence

Endpoints

MéthodeEndpointDescription
POST/ecr/authÉchange votre jeton API et un merchantToken contre un jeton d’accès.
POST/ecr/auth/refreshRenouvelle un jeton d’accès encore valide.
GET/ecr/devicesListe les appareils du commerçant. Filtre connected=true facultatif.
GET/ecr/devices/{externalDeviceId}Renvoie un appareil et sa disponibilité actuelle.
POST/ecr/payment-requestsEnregistre une demande de paiement et avertit l’appareil. Nécessite Idempotency-Key.
GET/ecr/payment-requests/{requestId}Renvoie le statut de la demande, l’éventuel motif de refus et le paymentToken.
POST/ecr/webhook-subscriptionsEnregistre une URL HTTPS et des types d’événements. Renvoie le signing secret (secret de signature) une seule fois.
GET/ecr/webhook-subscriptionsListe vos abonnements pour le commerçant, sans les signing secrets.
DELETE/ecr/webhook-subscriptions/{subscriptionId}Supprime un abonnement.

Disponibilité des appareils

Les deux endpoints d’appareils renvoient externalDeviceId, name, connected, availability, lastSeenAt et updatedAt.

ValeurDescription
readyConnecté, et capable de recevoir et d’afficher une demande.
busyTraite un paiement ou détient une demande active.
unavailableDéconnecté, sans session valide, ou incapable d’afficher l’écran de paiement.

Statuts des demandes

StatutDescription
pendingEnregistrée et en attente d’acceptation par l’appareil.
acknowledgedL’appareil l’a reçue ; le paiement n’existe peut-être pas encore.
payment_createdUn paiement et son paymentToken existent. Suivez la suite de la progression sur le paiement.
rejectedL’appareil ou Tapaya a refusé la demande.

Erreurs

CodeMotifDescription
403 / 404Objet indisponibleVous n’avez pas l’autorisation, ou l’objet n’existe pas.
409device_busyL’appareil a déjà une demande ou un paiement actif.
409device_unavailableL’appareil est connecté mais n’est pas prêt.
409idempotency_conflictLa clé a déjà été utilisée avec un corps différent.
503device_offlineL’appareil n’est pas connecté.

Les erreurs de validation du montant et de la devise suivent les mêmes conventions que le reste de la Platform API.

Événements webhook

ÉvénementEnvoyé lorsqueContenu de data
device.connectedUn appareil ouvre une nouvelle connexion active.externalDeviceId, connected, availability, lastSeenAt
device.disconnectedLa connexion se ferme ou la vérification d’activité expire.externalDeviceId, connected, availability, lastSeenAt
device.availability_changedLa disponibilité passe de l’une à l’autre des valeurs ready, busy et unavailable.externalDeviceId, availability, reason facultatif
payment_request.updatedLa demande est enregistrée, reçue, refusée, expire ou se voit associer un paiement.requestId, externalDeviceId, status, paymentToken, reference, reason, expiresAt
payment.updatedLe statut du paiement change.paymentToken, requestId, externalDeviceId, status, reference, amount, currency, receiptUrl facultatif

Chaque événement arrive sous forme de POST HTTP dans la même enveloppe :

{
    "eventId": "...",
    "type": "payment_request.updated",
    "occurredAt": "2026-01-13T16:30:59Z",
    "data": {
        "requestId": "...",
        "externalDeviceId": "till-01",
        "status": "acknowledged",
        "paymentToken": null,
        "reference": "ORDER-1042",
        "reason": null,
        "expiresAt": "2026-01-13T16:30:59Z"
    }
}
Il manque quelque chose sur cette page ?Demandez une fonctionnalité. Nous joignons cette page pour que l’équipe ait le contexte.