API

Paiement en magasin : Android Intent API

Présentation

L'Android Intent API est destinée aux applications de logiciel de caisse exécutées sur le terminal lui-même (ou sur le même appareil Android que Yavin Pay). Votre application envoie un Intent de deep link à Yavin Pay et reçoit le résultat dans onActivityResult. Choisissez-la lorsque le logiciel de caisse et l'application de paiement partagent le même appareil.

En bref

URL de baseSchéma de deep link : yavin://com.yavin.macewindu/v4/<action>?data=$queryParams
AuthentificationConnexion du marchand dans Yavin Pay avec ses identifiants My Yavin
Convention de nommagecamelCase pour tous les champs, sauf les entrées de tax_breakdown qui sont en snake_case
Version actuellev4
Remise des résultatsSynchrone : renvoyée à votre activité via onActivityResult, dans l'extra response (JSON) et, en cas d'erreur, dans l'extra message

Endpoints

ActionDeep linkUsage
Paiement/v4/paymentDémarrer une transaction de débit ou de remboursement
Impression/v4/printImprimer du contenu libre
Partager un ticket/v4/share-receiptPartager un ticket par SMS, e-mail ou impression
Transactions/v4/transactionsRécupérer l'historique des transactions
Annulation/v4/reversalAnnuler une transaction récente (de moins de 16 heures)
Lecteur NFC/v4/nfc-readerLire un tag NFC via Yavin Pay

Versions

Version de l'APIDernière mise à jour
v422/08/2024
v102/05/2022

Avant de commencer

Envoi de la requête

  • Encodage du payload : la requête est un objet JSON sérialisé puis encodé en URI dans le paramètre de requête data du deep link
  • Code de requête : lors de l'appel à startActivityForResult, définissez votre propre code de requête (un entier quelconque, par ex. 8888). Il vous sert de référence pour associer la réponse asynchrone à la requête, comme un identifiant de corrélation de webhook

Lecture de la réponse

  • Le JSON de résultat se trouve dans l'extra response
  • Lorsqu'un message d'erreur existe, il se trouve dans un extra message distinct, jamais dans le JSON response
  • L'extra response peut être absent (par exemple lorsque la requête est rejetée avant toute création de transaction, ou lorsque data est lui-même null) : lisez les extras de manière défensive et ne transmettez jamais une chaîne null à votre parseur JSON

Réponses

  • Les actions de paiement renvoient un objet Transaction, documenté à la fin de cette page avec les autres objets partagés, comportant un champ status : ok en cas de succès, ko en cas d'échec
  • Les clés dont la valeur est null sont omises : tolérez l'absence de clés
  • L'action transactions n'a pas de champ status (voir Récupérer les transactions)

N'envoyez jamais de montant négatif. Sur l'Android Intent API, le terminal ne rejette pas un amount ou un giftAmount négatif : il utilise sa valeur absolue. Un amount de -1000 est traité comme un paiement de 10,00 €. Validez les montants côté logiciel de caisse avant d'envoyer l'Intent.

Kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode != REQUEST_CODE_PAYMENT) return

    // Both extras are optional: data can be null (eg resultCode == RESULT_CANCELED)
    val json: String? = data?.getStringExtra("response")
    val message: String? = data?.getStringExtra("message")

    if (json == null) {
        // No transaction was returned: treat the attempt as failed
        onPaymentFailed(message ?: "No response from Yavin Pay (resultCode=$resultCode)")
        return
    }

    val response = Gson().fromJson(json, TransactionResponse::class.java)
    if (response.status == "ok") {
        onPaymentSucceeded(response)
    } else {
        // A declined payment carries no message in the JSON: use the message extra if any
        onPaymentFailed(message ?: "Payment declined")
    }
}

Idempotence

Envoyez un idempotentUuid à chaque requête de paiement, un par tentative de paiement. Voir Gestion de l'IdempotentUuid.

Devise

La devise est celle configurée sur le profil du marchand dans la base de données Yavin.


Lancer une transaction de débit

Lance un paiement par débit sur le terminal.

Paramètres

amountIntegerrequis
Montant en centimes, doit être supérieur à 0. N'envoyez jamais de valeur négative : elle n'est pas rejetée et sa valeur absolue est débitée
transactionTypeStringpar défaut debit
Utilisez debit. Les valeurs sont strictes (debit ou refund) : toute autre valeur, y compris credit, est traitée silencieusement comme un débit
idempotentUuidStringpar défaut autogenerated
Identifiant unique de la tentative de paiement, voir Gestion de l'IdempotentUuid. Une transaction ko est renvoyée telle quelle : générez un nouvel UUID pour réessayer
customerCustomer
Informations client préremplies pour l'envoi du ticket
Afficher les paramètres de Customer
customer.firstNameString
Prénom
customer.lastNameString
Nom
customer.emailString
E-mail
customer.phoneString
Format international commençant par +
customer.birthDateString
Date de naissance
enableGiftScreenBoolean
true : affiche l'écran de pourboire. false : l'ignore
giftAmountIntegerpar défaut 0
Pourboire ou don en centimes
receiptTicketReceiptTicket
Ticket imprimé avec le ticket carte
Afficher les paramètres de ReceiptTicket
receiptTicket.dataStringrequis
Contenu à imprimer
receiptTicket.formatStringpar défaut text
Format du contenu
receiptTicket.tax_breakdownArray
Tableau d'objets Tax, un par taux de taxe
receiptTicketJsonString
Payload JSON supplémentaire sous forme de chaîne
referenceString
Serveur ou personne qui traite la transaction
vendorVendor
Nom et version de votre logiciel
Afficher les paramètres de Vendor
vendor.softwareNameString
Nom du logiciel de caisse
vendor.softwareVersionString
Version du logiciel de caisse
checkoutExternalIdString
Identifiant de commande unique du marchand, obligatoire dès qu'un des champs de commande externe ci-dessous est envoyé. Il doit être unique : une requête est rejetée si une transaction ok terminée utilise déjà cette valeur
externalTableNumberString
Numéro de table. Nécessite checkoutExternalId
externalOrderNumberString
Numéro de commande lisible. Nécessite checkoutExternalId
externalOrderIdString
Identifiant technique unique de la commande dans votre logiciel de caisse, pour le rapprochement. Nécessite checkoutExternalId

Requête

Kotlin
val request = TransactionRequest(
  amount = 100,
  transactionType = "debit",
  idempotentUuid = "2f1c2e2a-6c21-4a4b-9c2b-9f6f2c8e9b51",
  customer = Customer("John", "Doe", "john@yavin.com"),
  vendor = Vendor("Awesome Partner", "1.2.3"),
  receiptTicket = ReceiptTicket(data = "This is a wonderful\n receipt ticket to print", format = "text"),
  receiptTicketJson = JSONObject("{\"transactionId\": \"123456\", \"amount\": 3500 }").toString(),
  checkoutExternalId = "order-123",
  externalTableNumber = "12",
  externalOrderNumber = "A-123",
  externalOrderId = "order-123"
)

val jsonData = Gson().toJson(request)
val queryParams = Uri.encode(jsonData)

val intent = Intent(Intent.ACTION_VIEW).apply {
  data = Uri.parse("yavin://com.yavin.macewindu/v4/payment?data=$queryParams")
}

startActivityForResult(intent, REQUEST_CODE_PAYMENT)

Réponse

En cas de succès, la réponse est un objet Transaction avec status = ok et un transactionId ; les champs de la requête (reference, customer, idempotentUuid, checkoutExternalId et les champs de commande externe) sont renvoyés à l'identique.

Si une transaction existe déjà pour cet idempotentUuid, elle est renvoyée telle quelle, y compris lorsqu'elle est encore en cours : dans ce cas, elle n'a pas de champ status.

En cas d'échec, l'extra response contient un objet Transaction avec status = ko et sans message. Lorsqu'il y a un message d'erreur, il se trouve dans l'extra distinct message. Lorsque la requête est rejetée avant la création d'une transaction, l'extra response est absent et seul message est renseigné. Messages possibles :

  • Error: refund need to be activated contact support : les remboursements ne sont pas activés pour ce marchand
  • Transaction cannot proceed: unknown payment gateway or amount is not greater than 0
  • Error: amount exceeds the maximum authorized credit amount (N) : remboursement supérieur au montant maximal autorisé N
  • Error: checkoutExternalId must not be null if any of the following values are provided: externalOrderId, externalOrderNumber, externalTableNumber, or items : un champ de commande externe a été envoyé sans checkoutExternalId
  • Error: checkoutExternalId: The checkoutExternalId is already in use. Please ensure you provide a unique value : une transaction ok terminée utilise déjà ce checkoutExternalId
  • A request is already in progress : une autre requête est en cours
  • Un message de délai dépassé lorsque les écrans facultatifs (pourboire, référence, récapitulatif) dépassent 60 secondes
  • Unknown Error ou un message d'exception : erreur interne Android

Lancer une transaction de remboursement

Rembourse des fonds sur la carte du client. Même deep link et même payload que pour le débit, avec transactionType défini sur refund.

Paramètres

transactionTypeStringrequispar défaut debit
Doit être défini sur refund. Toute autre valeur, telle que credit, lance un débit

Réponse

Identique à l'action de débit : un objet Transaction avec transactionType = refund en cas de succès, status = ko avec la même liste de messages en cas d'échec.


Partager un ticket

Partage un ticket par SMS, e-mail ou impression. Si customer est fourni, le ticket est envoyé directement ; sinon, le terminal demande les informations manquantes.

Paramètres

receiptTicketReceiptTicketrequis
Ticket à partager
Afficher les paramètres de ReceiptTicket
receiptTicket.dataStringrequis
Contenu à imprimer
receiptTicket.formatStringpar défaut text
Format du contenu
receiptTicket.tax_breakdownArray
Tableau d'objets Tax, un par taux de taxe
transactionIdStringrequis
Transaction liée au ticket
mediumStringrequis
L'une des valeurs yavin, sms, email, print. Avec yavin, le ticket est enregistré et partagé selon les préférences de notification de l'utilisateur
customerCustomer
Informations du destinataire pour le SMS ou l'e-mail
Afficher les paramètres de Customer
customer.firstNameString
Prénom
customer.lastNameString
Nom
customer.emailString
E-mail
customer.phoneString
Format international commençant par +
customer.birthDateString
Date de naissance

Requête

Kotlin
val request = ShareRequest(
  receiptTicket = ReceiptTicket(format = "text", data = "Text to print"),
  transactionId = "gks15fQSfw",
  medium = "email",
  customer = Customer("John", "Doe", email = "john@yavin.com")
)
val queryParams = Uri.encode(Gson().toJson(request))
val intent = Intent(Intent.ACTION_VIEW).apply {
  data = Uri.parse("yavin://com.yavin.macewindu/v4/share-receipt?data=$queryParams")
}
startActivityForResult(intent, REQUEST_CODE_SHARE)

Réponse

status = ok lorsque le ticket a été partagé. En cas d'échec, status = ko avec l'un des messages suivants :

  • Error: transaction with id ${transactionId} not found on the terminal
  • Error: phone number must follow the international format starting with + symbol
  • Error: wrong parameter 'medium' : possible values are 'yavin', 'print', 'sms' or 'email' : moyen de partage manquant ou invalide
  • Error: wrong deeplink input data : requête mal formatée
  • Error: transaction is missing : transactionId manquant

Récupérer les transactions

Récupère les transactions du terminal. Utilisez limit et offset pour la pagination. Si aucun filtre de date n'est défini, les 30 derniers jours sont récupérés.

Paramètres

startDateStringpar défaut last 30 days
Date de début incluse, ISO 8601
endDateStringpar défaut today
Date de fin incluse, ISO 8601
startTimeStringpar défaut 00:00:00Z
Heure de début le startDate, ISO 8601
endTimeStringpar défaut 23:59:59Z
Heure de fin le endDate, ISO 8601
limitIntegerpar défaut 50
Nombre maximal de transactions renvoyées, jusqu'à 200
offsetIntegerpar défaut 0
Décalage de pagination

Requête

Kotlin
val request = TransactionsRequest(
  startDate = "2022-01-01",
  endDate = "2022-02-01",
  startTime = "00:00:00",
  endTime = "23:59:59",
  limit = 50
)
val queryParams = Uri.encode(Gson().toJson(request))
val intent = Intent(Intent.ACTION_VIEW).apply {
  data = Uri.parse("yavin://com.yavin.macewindu/v4/transactions?data=$queryParams")
}
startActivityForResult(intent, REQUEST_CODE_TRANSACTIONS)

Réponse

Renvoie total, count, limit, offset et transactions. Il n'y a pas de champ status.

  • total correspond au nombre de transactions dans cette réponse (égal à count), et non au nombre total de transactions correspondantes. Pour paginer, augmentez offset de limit jusqu'à ce qu'une page renvoie moins de limit transactions.
  • Chaque élément de transactions contient les champs de ItemTransactionResponse ci-dessus. Il s'agit d'un objet réduit, et non de l'objet Transaction complet : il ne contient ni cardToken, ni paymentApplication, ni tickets, ni idempotentUuid.
  • createdAt est l'horodatage de la transaction sur le terminal, en ISO 8601 UTC.

Si data est absent ou invalide, aucune réponse n'est renvoyée et l'écran Yavin Pay reste ouvert. Validez la requête côté logiciel de caisse avant de l'envoyer.


Annuler une transaction

Annule une transaction récente.

Conditions d'annulation. La transaction d'origine est un débit ok traité sur le même terminal que celui qui émet l'annulation, il y a moins de 16 heures (heure du terminal), et le montant de l'annulation est égal au montant total d'origine, pourboire inclus (amount + giftAmount).

Paramètres

amountIntegerrequispar défaut 0
Montant en centimes, doit être égal au montant total d'origine (amount • giftAmount)
initialTransactionIdStringrequis
Transaction à annuler

Réponse

status = ok avec reversalTransactionId (la nouvelle transaction d'annulation) et initialTransactionId (la transaction annulée). En cas d'échec, status = ko avec l'une des valeurs suivantes :

  • Transaction ID is mandatory : initialTransactionId manquant
  • Transaction not found for ID: <transactionId> : transaction inconnue sur ce terminal
  • Amount mismatch : le montant diffère du montant total d'origine (amount + giftAmount)
  • Transaction has already been reversed
  • Cannot reverse this Transaction or time window expired : la transaction n'est pas une transaction de débit ok ou VAD, ou date de plus de 16 heures
  • No suitable gateway found to handle reversal
  • An unexpected error occurred. Please try again later. : erreur générique

Champs inversés en cas d'erreur. Dans une réponse d'erreur, reversalTransactionId contient l'ID de la transaction initiale et initialTransactionId contient l'ID de la tentative d'annulation. Lisez-les en conséquence.


Lire un tag NFC via Pay

Lit un tag NFC via Yavin Pay.

Paramètres

readerIncentiveString
Texte affiché pendant l'attente du tag
timeoutLongpar défaut 10000
Délai de lecture en millisecondes, maximum 10000 : une valeur supérieure est plafonnée à 10000

Requête

Kotlin
val request = NFCReaderRequestV4(10000, "Approchez votre carte")
val queryParams = Uri.encode(Gson().toJson(request))
val intent = Intent(Intent.ACTION_VIEW).apply {
  data = Uri.parse("yavin://com.yavin.macewindu/v4/nfc-reader?data=$queryParams")
}
startActivityForResult(intent, REQUEST_CODE_READ)

Réponse

status est un booléen : true avec un objet TagInfo lorsque le tag a été lu, false sinon.


L'objet Transaction

Renvoyé par les actions de paiement. Les champs provenant de votre requête sont renvoyés tels quels. Les clés dont la valeur est null sont omises : tolérez les clés manquantes. Un paiement refusé a status = ko et aucun message (voir Lecture de la réponse).

Attributs

statusString
ok ou ko. Absent pour une transaction en cours
transactionIdString
Identifiant côté serveur
amountInteger
Montant en centimes, hors giftAmount
giftAmountInteger
Pourboire ou don en centimes
currencyCodeString
Code ISO 4217
transactionTypeString
En minuscules : debit ou refund. Tolérez les autres valeurs (par ex. na)
appVersionString
Version de l'application Yavin Pay
cardTokenString
Token unique de la carte du client
clientCardTicket / merchantCardTicketString
Tickets de carte du client et du marchand
paymentApplicationString
par ex. EMV_CONTACTLESS
schemeString
Réseau d'acceptation (par ex. VISA)
issuerString
Émetteur de la carte
idempotentUuidString
UUID issu de la requête
reference, customer
Renvoyé tel quel depuis la requête
checkoutExternalId, externalTableNumber, externalOrderNumber, externalOrderIdString
Renvoyé tel quel depuis la requête

JSON
{
  "status": "ok",
  "transactionId": "xPUyi4fmdibD",
  "amount": 1000,
  "giftAmount": 0,
  "currencyCode": "EUR",
  "transactionType": "debit",
  "appVersion": "3.2.8",
  "cardToken": "1234567890",
  "clientCardTicket": "...",
  "merchantCardTicket": "...",
  "paymentApplication": "EMV_CONTACTLESS",
  "scheme": "CB",
  "issuer": "VISA",
  "idempotentUuid": "2f1c2e2a-6c21-4a4b-9c2b-9f6f2c8e9b51",
  "cartId": "ORDER-2026-000123",
  "reference": "Luke",
  "customer": {
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@yavin.com"
  },
  "checkoutExternalId": "order-123",
  "externalTableNumber": "12",
  "externalOrderNumber": "A-123",
  "externalOrderId": "order-123"
}

L'objet Customer

Facultatif pour les actions de paiement et de partage de ticket. Préremplit les informations du client afin que le ticket puisse être envoyé par SMS ou e-mail sans demande sur le terminal.

Attributs

firstNameString
Prénom
lastNameString
Nom
emailString
E-mail
phoneString
Format international commençant par +
birthDateString
Date de naissance

JSON
{
  "customer": {
    "firstName": "John",
    "lastName": "Doe",
    "phone": "+33612345678",
    "email": "john@yavin.com"
  }
}

L'objet ReceiptTicket

Contenu imprimé avec le ticket de carte lors de l'action de paiement, ou partagé lors de l'action de partage de ticket.

Attributs

dataStringrequis
Contenu à imprimer
formatStringpar défaut text
Format du contenu
tax_breakdownArray
Tableau d'objets Tax, un par taux de taxe

JSON
{
  "receiptTicket": {
    "data": "Receipt ticket here to print if needed",
    "format": "text"
  }
}

L'objet Tax

Ventilation facultative associée à un ReceiptTicket, sous la clé tax_breakdown, avec une entrée par taux de taxe.

La clé est tax_breakdown (et non tax), et ses entrées sont en snake_case.

Attributs

tax_amountInteger
Montant de taxe calculé en centimes
tax_percentageInteger
Pourcentage appliqué au montant (par ex. 20 pour 20 %)

JSON
{
  "tax_breakdown": [
    { "tax_amount": 167, "tax_percentage": 20 },
    { "tax_amount": 50, "tax_percentage": 10 }
  ]
}

L'objet Vendor

Identifie votre logiciel de caisse. Facultatif partout, mais fortement recommandé : il permet à notre équipe support de remonter d'un problème à une intégration et une version précises.

Attributs

softwareNameString
Nom du logiciel de caisse
softwareVersionString
Version du logiciel de caisse

JSON
{
  "vendor": {
    "softwareName": "MyPOS",
    "softwareVersion": "1.0"
  }
}

L'objet TagInfo

Renvoyé par l'action du lecteur NFC, il décrit le tag qui a été lu.

Attributs

serialNumberString
Identifiant du tag

JSON
{
  "tagInfo": {
    "serialNumber": "04A2B3C4D5E6F7"
  }
}