API

In-store payment: Android Intent API

Overview

The Android Intent API is for POS applications running on the terminal itself (or on the same Android device as Yavin Pay). Your app sends a deep link Intent to Yavin Pay and receives the result in onActivityResult. Choose it when the POS and the payment application share the same device.

At a glance

Base URLDeep link scheme: yavin://com.yavin.macewindu/v4/<action>?data=$queryParams
AuthenticationMerchant login in Yavin Pay with My Yavin credentials
Naming conventioncamelCase for all fields, except the entries of tax_breakdown which are snake_case
Current versionv4
Result deliverySynchronous: returned to your activity via onActivityResult, in the response extra (JSON) and, on error, the message extra

Endpoints

ActionDeep linkPurpose
Payment/v4/paymentStart a debit or refund transaction
Print/v4/printPrint free content
Share receipt/v4/share-receiptShare a receipt by SMS, email or print
Transactions/v4/transactionsFetch the transaction history
Reversal/v4/reversalReverse a recent transaction (less than 16 hours old)
NFC reader/v4/nfc-readerRead an NFC tag via Yavin Pay

Versions

API versionLast updated
v422/08/2024
v102/05/2022

Before you start

Payload encoding. The request is a JSON object serialized then URI-encoded into the data query parameter of the deep link.

Request code. When calling startActivityForResult, define your own request code (any integer, eg 8888). It is your reference to match the asynchronous response with the request, similar to a webhook correlation ID.

Reading the response. The result JSON is in the response extra. When an error message exists, it is in a separate message extra, never inside the response JSON. The response extra can be absent (for example when the request is rejected before any transaction is created, or when data itself is null): read the extras defensively and never pass a null string to your JSON parser.

Responses. The payment actions return a Transaction object, documented at the end of this page along with the other shared objects, with a status field: ok on success, ko on failure. Keys whose value is null are omitted: tolerate missing keys. The transactions action has no status field (see Fetch transactions).

Never send a negative amount. On the Android Intent API, the terminal does not reject a negative amount or giftAmount: it uses its absolute value. An amount of -1000 is processed as a 10,00 € payment. Validate amounts on the POS side before sending the Intent.

Idempotency. Send an idempotentUuid on every payment request, one per payment attempt. See IdempotentUuid Management.

Currency. The currency is the one configured on the merchant profile in the Yavin database.


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")
    }
}

Start a debit transaction

Starts a debit payment on the terminal.

Parameters

amountIntegerrequired
Amount in cents, must be greater than 0. Never send a negative value: it is not rejected and its absolute value is charged
transactionTypeStringdefault debit
Use debit. Values are strict (debit or refund): any other value, credit included, is silently processed as a debit
idempotentUuidStringdefault autogenerated
Unique identifier of the payment attempt, see IdempotentUuid Management. A ko transaction is returned as is: generate a new UUID to retry
customerCustomer
Pre-filled customer info for receipt sharing
Show Customer parameters
customer.firstNameString
First name
customer.lastNameString
Last name
customer.emailString
Email
customer.phoneString
International format starting with +
customer.birthDateString
Birthdate
enableGiftScreenBoolean
true: show the tips screen. false: skip it
giftAmountIntegerdefault 0
Tip or donation in cents
receiptTicketReceiptTicket
Receipt printed with the card ticket
Show ReceiptTicket parameters
receiptTicket.dataStringrequired
Content to print
receiptTicket.formatStringdefault text
Format of the content
receiptTicket.tax_breakdownArray
Array of Tax objects, one per tax rate
receiptTicketJsonString
Additional JSON payload as string
referenceString
Waiter or person processing the transaction
vendorVendor
Your software name and version
Show Vendor parameters
vendor.softwareNameString
Name of the POS software
vendor.softwareVersionString
Version of the POS software
checkoutExternalIdString
Merchant-unique checkout ID, required when any external order field below is sent. It must be unique: a request is rejected if a completed ok transaction already uses this value
externalTableNumberString
Table number. Requires checkoutExternalId
externalOrderNumberString
Human-readable order number. Requires checkoutExternalId
externalOrderIdString
Unique technical order ID from your POS, for reconciliation. Requires checkoutExternalId

Request

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)

Response

On success, the response is a Transaction object with status = ok and a transactionId; the request fields (reference, customer, idempotentUuid, checkoutExternalId and the external order fields) are echoed back.

If a transaction already exists for this idempotentUuid, it is returned as is, including when it is still in progress: in that case it has no status field.

On failure, the response extra contains a Transaction object with status = ko and no message. When there is an error message, it is in the separate message extra. When the request is rejected before a transaction is created, the response extra is absent and only message is set. Possible messages:

  • Error: refund need to be activated contact support: refunds are not enabled for this merchant
  • Transaction cannot proceed: unknown payment gateway or amount is not greater than 0
  • Error: amount exceeds the maximum authorized credit amount (N): refund above the maximum authorized amount N
  • Error: checkoutExternalId must not be null if any of the following values are provided: externalOrderId, externalOrderNumber, externalTableNumber, or items: an external order field was sent without checkoutExternalId
  • Error: checkoutExternalId: The checkoutExternalId is already in use. Please ensure you provide a unique value: a completed ok transaction already uses this checkoutExternalId
  • A request is already in progress: another request is in progress
  • A timeout message when the optional screens (tips, reference, review) exceed 60 seconds
  • Unknown Error or an exception message: Android internal error

Start a refund transaction

Credits funds back to the customer card. Same deep link and payload as debit, with transactionType set to refund.

Parameters

transactionTypeStringrequireddefault debit
Must be set to refund. Any other value, such as credit, starts a debit

Response

Same as the debit action: a Transaction object with transactionType = refund on success, status = ko with the same message list on failure.


Share a receipt ticket

Shares a receipt by SMS, email or print. If customer is provided the receipt is sent directly; otherwise the terminal prompts for the missing information.

Parameters

receiptTicketReceiptTicketrequired
Receipt to share
Show ReceiptTicket parameters
receiptTicket.dataStringrequired
Content to print
receiptTicket.formatStringdefault text
Format of the content
receiptTicket.tax_breakdownArray
Array of Tax objects, one per tax rate
transactionIdStringrequired
Transaction linked to the receipt
mediumStringrequired
One of yavin, sms, email, print. With yavin, the receipt is stored and shared according to the user notification preferences
customerCustomer
Recipient info for SMS or email
Show Customer parameters
customer.firstNameString
First name
customer.lastNameString
Last name
customer.emailString
Email
customer.phoneString
International format starting with +
customer.birthDateString
Birthdate

Request

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)

Response

status = ok when the receipt was shared. On failure, status = ko with one of:

  • 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': medium missing or invalid
  • Error: wrong deeplink input data: badly formatted request
  • Error: transaction is missing: transactionId missing

Fetch transactions

Retrieves the transactions of the terminal. Use limit and offset for pagination. If no date filters are set, the last 30 days are fetched.

Parameters

startDateStringdefault last 30 days
Earliest date to include, ISO 8601
endDateStringdefault today
Latest date to include, ISO 8601
startTimeStringdefault 00:00:00Z
Start time on startDate, ISO 8601
endTimeStringdefault 23:59:59Z
End time on endDate, ISO 8601
limitIntegerdefault 50
Max transactions returned, up to 200
offsetIntegerdefault 0
Pagination offset

Request

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)

Response

Returns total, count, limit, offset, and transactions. There is no status field.

  • total is the number of transactions in this response (equal to count), not the total number of matching transactions. To paginate, increase offset by limit until a page returns fewer than limit transactions.
  • Each item of transactions has the fields of ItemTransactionResponse above. It is a reduced object, not the full Transaction object: it has no cardToken, paymentApplication, tickets or idempotentUuid.
  • createdAt is the terminal timestamp of the transaction, in ISO 8601 UTC.

If data is missing or invalid, no response is returned and the Yavin Pay screen stays open. Validate the request on the POS side before sending it.


Reverse a transaction

Reverses a recent transaction.

Reversal conditions. The original transaction is an ok debit processed on the same terminal issuing the reversal, less than 16 hours ago (terminal time), and the reversal amount is equal to the original total amount, tip included (amount + giftAmount).

Parameters

amountIntegerrequireddefault 0
Amount in cents, must equal the original total amount (amount • giftAmount)
initialTransactionIdStringrequired
Transaction to reverse

Response

status = ok with reversalTransactionId (the new reversal transaction) and initialTransactionId (the reversed one). On failure, status = ko with one of:

  • Transaction ID is mandatory: initialTransactionId missing
  • Transaction not found for ID: <transactionId>: unknown transaction on this terminal
  • Amount mismatch: amount differs from the original total amount (amount + giftAmount)
  • Transaction has already been reversed
  • Cannot reverse this Transaction or time window expired: the transaction is not an ok debit or VAD transaction, or is more than 16 hours old
  • No suitable gateway found to handle reversal
  • An unexpected error occurred. Please try again later.: generic error

Swapped fields on error. In an error response, reversalTransactionId contains the ID of the initial transaction, and initialTransactionId contains the ID of the reversal attempt. Read them accordingly.


Read NFC tag via Pay

Reads an NFC tag through Yavin Pay.

Parameters

readerIncentiveString
Text displayed while waiting for the tag
timeoutLongdefault 10000
Read timeout in milliseconds, maximum 10000: a higher value is capped at 10000

Request

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)

Response

status is a boolean: true with a TagInfo object when the tag was read, false otherwise.


The Transaction object

Returned by the payment actions. Fields coming from your request are echoed back as is. Keys whose value is null are omitted: tolerate missing keys. A declined payment has status = ko and no message (see Reading the response).

Attributes

statusString
ok or ko. Absent on a transaction still in progress
transactionIdString
Server-side identifier
amountInteger
Amount in cents, excluding giftAmount
giftAmountInteger
Tip or donation in cents
currencyCodeString
ISO 4217 code
transactionTypeString
Lowercase: debit or refund. Tolerate other values (eg na)
appVersionString
Yavin Pay app version
cardTokenString
Unique token of the customer card
clientCardTicket / merchantCardTicketString
Customer and merchant card tickets
paymentApplicationString
eg EMV_CONTACTLESS
schemeString
Acceptance network (eg VISA)
issuerString
Card issuer
idempotentUuidString
UUID from the request
reference, customer
Echoed from the request
checkoutExternalId, externalTableNumber, externalOrderNumber, externalOrderIdString
Echoed from the request

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"
}

The Customer object

Optional on the payment and share-receipt actions. Pre-fills the customer information so the receipt can be sent by SMS or email without prompting on the terminal.

Attributes

firstNameString
First name
lastNameString
Last name
emailString
Email
phoneString
International format starting with +
birthDateString
Birthdate

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

The ReceiptTicket object

Content printed alongside the card ticket on the payment action, or shared on the share-receipt action.

Attributes

dataStringrequired
Content to print
formatStringdefault text
Format of the content
tax_breakdownArray
Array of Tax objects, one per tax rate

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

The Tax object

Optional breakdown attached to a ReceiptTicket, under the tax_breakdown key, with one entry per tax rate.

The key is tax_breakdown (not tax), and its entries are in snake_case.

Attributes

tax_amountInteger
Calculated tax amount in cents
tax_percentageInteger
Percentage applied to the amount (eg 20 for 20%)

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

The Vendor object

Identifies your POS software. Optional everywhere, but strongly recommended: it is what lets our support team trace an issue back to a specific integration and version.

Attributes

softwareNameString
Name of the POS software
softwareVersionString
Version of the POS software

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

The TagInfo object

Returned by the NFC reader action, describing the tag that was read.

Attributes

serialNumberString
Tag identifier

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