Sale request
An overview of the Sale request message for iOS.
Our ‘Viva.com Terminal’ application (tap-on-phone) supports Apple Tap to Pay Austria, Belgium, Bulgaria, Croatia, Cyprus, Czech Republic, Denmark, Finland, France, Germany, Greece, Hungary, Ireland, Italy, Luxembourg, Malta, Poland, Portugal, Romania, Spain, Sweden, the Netherlands, Norway, the UK.
Overview
👉 The Sale request is used to prompt payment from the customer for a specific amount, including the desired tip amount. Once the customer has attempted or completed payment, a related transaction (either successful or unsuccessful) will be created.
The client app must implement a mechanism to send messages using URL schemes and to receive the result in a custom URI callback.
- Sale request originating from the client app to initiate a request for a new Sale transaction.
- Sale response originating from the Viva.com Terminal App to return the result of a Sale transaction.
Sale request
For a typical Sale request, the client app must provide the following information:
Field | Description | Example | Required |
---|---|---|---|
scheme | The Viva custom URL scheme, the host and the version. | 'vivapayclient://pay/v1' | ✅ |
merchantKey | The merchant's key. For successful validation, should not be empty. Deprecated: you may pass any value. |
'SG23323424EXS3' | |
appId | The client app id. | 'com.example.myapp' | ✅ |
action | Sale transaction. | 'sale' | ✅ |
clientTransactionId | A unique transaction ID transmitted to the host for storage with the transaction. Note that this value will be provided in the Merchant Reference field provided in the sales export response. | '12345678901234567890123456789012' | |
amount | Amount in cents without any decimal digits. This value must not be empty and must be an integer larger than zero. | '1200' = 12 euro | ✅ |
tipAmount | The tip that will be added on top of the amount. This must be less than or equal to the amount. | '200' = 2 euro | |
withInstallments | Enable card installments. Only in Greek Merchant | 'true' | |
preferredInstallments | Number of preferred card installments. Only in Greek Merchants. If the number is between the allowed range and the card supports installments then the flow complete without any prompt for installments. If the number is 0 or > max allowed number of installments then the user will be prompt to enter the number in the app. If the card does not support installments then the app will request from the user how to proceed with the flow. If withInstallments is true preferredInstallments must be integer and not empty. | '10' | |
paymentMethod | The payment method to be presented first to the user.
The same time, the user is able to select another payment method |
Choose one of the following values:
|
|
show_receipt | Option to show the receipt screen, before returning to the InterApp, after performing a sale on Viva.com Terminal App. | 'false' | |
show_transaction_result | Option to show the transaction result screen, before returning to the InterApp, after performing a sale on Viva.com Terminal App. If show_receipt is set to 'true’ this value will be neglected, therefore the transaction result screen will be shown. | 'false' | |
ISV_amount | The fee charged by the ISV on the sale. Amount in cents. Only for ISV Partners | '10' =0.1€ | Required for ISV integration |
ISV_clientId | The id of the ISV client. It is mandatory that if client id is provided the ISV_amount and ISV_clientSecret parameters should be provided too. Only for ISV PartnersRefer to note below. |
'xxxxx.apps.vivapayments.com' | Required for ISV integration |
ISV_clientSecret | The secret of the ISV client. Only for ISV PartnersRefer to note below. |
'qtFskX94T2f2Dkhc364pa1cgaFn3D' | Required for ISV integration |
ISV_sourceCode | The source code of the ISV. Only for ISV PartnersRefer to note below. |
[A payment source (physical store) that is associated with a terminal] How to create a payment source for ISV |
|
ISV_merchantId | Support for merchant switching via the inter-app while utilizing ISV feature | '8d40824a-a5d3-4639-819c-6e8bddb99477' | |
ISV_merchantSourceCode | The merchant source code of the ISV | 'Default' | |
ISV_customerTrns | The ISV transaction description for customer | ‘qwerty123456’ | |
ISV_clientTransactionId | A unique transaction ID transmitted to the host for storage with the transaction of the ISV. Note that this value will be provided in the Merchant Reference field provided in the sales export response. | '12345678901234567890123456789012' | |
aadeProviderId [*] | 👉 Integration with Provider (ΥΠΑΗΕΣ) Set the Unique Number to identify your Provider. To learn more about all licensed AADE providers, please visit this page, and about their public keys visit this page. 👉 Integration with ΦΗΜΑΣ (Φορολογικός Ηλεκτρονικός Μηχανισμός Ασφαλείας) For integration through ΦΗΜΑΣ, please specify as `aadeProviderId' the value 800 |
Integration with Provider (ΥΠΑΗΕΣ) 999 Integration with ΦΗΜΑΣ (Φορολογικός Ηλεκτρονικός Μηχανισμός Ασφαλείας) 800 |
|
aadeProviderSignatureData [*] | 👉 Integration with Provider (ΥΠΑΗΕΣ) The unencrypted signature that includes the fields below with semicolon as a delimiter “;”: 👉 Integration with ΦΗΜΑΣ (Φορολογικός Ηλεκτρονικός Μηχανισμός Ασφαλείας) Use ECR TOKEN as in A.1098/2023 Request A/S< session number>/F< amount>:978:2 /D< datetime>/R< ecr-id>/H< operator-number>/T0 /M/Q< mac>} Result R/S< session number>/R< ecr-id>/T< receipt-number> /Μ/C00/D< trans-data>{/P< prn-data>}} |
Integration with Provider (ΥΠΑΗΕΣ) AD33729F4ED749928AAFA00B90EE4EA91551BAC1;;20231204080313;1051;10000;2400;12400;POS_1 |
|
aadeProviderSignature [*] | 👉 Integration with Provider (ΥΠΑΗΕΣ) The fields of providerSignatureFields encrypted using a public key and the Elliptic Curve Digital Signature Algorithm (ECDSA): 👉 Integration with ΦΗΜΑΣ (Φορολογικός Ηλεκτρονικός Μηχανισμός Ασφαλείας) Use SessionKey as in A.1098/2023 |
Integration with Provider (ΥΠΑΗΕΣ) o0094r3Yk3KTqASLkW3evlDsnIg/ZAdUUf6UCXDtjqpI/dquzAT4WNX3yzS/GLciVNbT75H4pj8hLOV0EpHtzw==" |
|
protocol | The protocol used (internal use only) | Always pass this value: int_default | |
callback | Your custom URI callback that will handle the result. | 'interapp-callback' | ✅ |
[*] These parameters are only applicable in Greece.
ISV parameter info:
- ISV_clientId can be found under Settings > API access in the viva banking app
- ISV_clientSecret as above.
- ISV_sourceCode is the payment source for ISV set up under Sales > Physical Payments > Stores.
Using the information above, our custom URI should be created like this.
typealias ISVDetails = (clientId: String, amount: Decimal, clientSecret: String, sourceCode: String?)
typealias AADEDetails = (receiptId: String, mark: String?, date: String, amountToBePayed: Int, sumAmountWithoutTAX: Int, vatPercentage: Int, sumAmountWithTAX: Decimal, tid: Int)
func createSaleRequest(
amount: Decimal,
tipAmount: Decimal?,
clientTransactionId: String?,
isvDetails: ISVDetails?,
numberOfInstallments: Int?,
aadeDetails: AADEDetails?,
aadeProviderId: Int?,
aadeProviderSignature: String?
) -> URL {
// construct sale action url
var saleActionURL = URL(string: Constants.saleUrlString) // vivapayclient://pay/v1?callback=interapp-callback&merchantKey=SG23323424EXS3&appId=com.vivawallet.InterAppDemo&action=sale
var urlQueryItems: [URLQueryItem] = []
let amountQueryItem = URLQueryItem(
name: "amount",
value: ((amount * 100) as Int).toString() // The amount in cents without any decimal digits.
)
urlQueryItems.append(amountQueryItem)
let tipQueryItem = URLQueryItem(
name: "tipAmount",
value: ((tip * 100) as Int).toString() // The tip amount in cents without any decimal digits.
)
urlQueryItems.append(tipQueryItem)
let transactionIdQueryItem = URLQueryItem(
name: "clientTransactionId",
value: clientTransactionId
)
urlQueryItems.append(transactionIdQueryItem)
// append number of installments parameter (if any)
var hasInstallments = false
if let preferredInstallments = numberOfInstallments, preferredInstallments > 1 {
let preferredInstallmentsQueryItem = URLQueryItem(
name: "preferredInstallments",
value: preferredInstallments.toString()
)
hasInstallments = true
}
let hasInstallmentsQueryItem = URLQueryItem(
name: "withInstallments",
value: "\(hasInstallments)"
)
urlQueryItems.append(preferredInstallmentsQueryItem)
urlQueryItems.append(hasInstallmentsQueryItem)
let isvQueryItems = getISVQueryItems(isvDetails: isvDetails)
urlQueryItems.append(contentsOf: isvQueryItems)
let showReceiptQueryItem = URLQueryItem(
name: "show_receipt",
value: (UserDefaults.standard.value(forKey: "show_receipt") as? Bool ?? true).toString()
)
urlQueryItems.append(showRatingQueryItem)
let showTransactionResultQueryItem = URLQueryItem(
name: "show_transaction_result",
value: (UserDefaults.standard.value(forKey: "show_transaction_result") as? Bool ?? true).toString()
)
urlQueryItems.append(showTransactionResultQueryItem)
let aadeQueryItems = getAADEQueryItems(
aadeDetails: aadeDetails,
aadeProviderId: aadeProviderId,
aadeProviderSignature: aadeProviderSignature
)
urlQueryItems.append(contentsOf: aadeQueryItems)
saleActionURL.append(queryItems: urlQueryItems.compactMap ({ $0.value }))
return saleActionURL
}
private func getISVQueryItems(isvDetails: isvDetails?) -> [URLQueryItem] {
guard let isvDetails else {
return []
}
// Add isvDetails
let isvClientIdQueryItem = URLQueryItem(
name: "ISV_clientId",
value: isvDetails.clientId
)
let isvAmountQueryItem = URLQueryItem(
name: "ISV_amount",
value: ((isvDetails.amount * 100) as Int).toString()// The ISV amount in cents without any decimal digits.
)
let isvClientSecretQueryItem = URLQueryItem(
name: "ISV_clientSecret",
value: isvDetails.clientSecret
)
let isvClientSecretQueryItem = URLQueryItem(
name: "ISV_sourceCode",
value: isvDetails.sourceCode
)
urlQueryItems.append(isvClientIdQueryItem)
urlQueryItems.append(isvAmountQueryItem)
urlQueryItems.append(isvClientSecretQueryItem)
urlQueryItems.append(isvClientSecretQueryItem)
return urlQueryItems.compactMap ({ $0.value })
}
private func getAADEQueryItems(
aadeDetails: AADEDetails?,
aadeProviderId: Int?,
aadeProviderSignature: String?
) -> [URLQueryItem] {
guard let aadeProviderId else {
return []
}
var urlQueryItems: [URLQueryItem] = []
let aadeProviderIdQueryItem = URLQueryItem(
name: "aadeProviderId",
value: aadeProviderId.toString()
)
urlQueryItems.append(aadeProviderIdQueryItem)
let value = """
\(aadeDetails?.receiptId);\(aadeDetails?.mark ?? "");\(aadeDetails?.date);\(aadeDetails?.amountToBePayed);
\(aadeDetails?.sumAmountWithoutTAX);\(aadeDetails?.vatPercentage);\(aadeDetails?.sumAmountWithTAX);\(aadeDetails?.tid)
"""
let aadeSignatureFieldsQueryItem = URLQueryItem(
name: "providerSignatureFields",
value: value
)
urlQueryItems.append(aadeSignatureFieldsQueryItem)
let aadeProviderSignatureQueryItem = URLQueryItem(
name: "aadeProviderSignature",
value: aadeProviderSignature
)
urlQueryItems.append(aadeProviderSignatureQueryItem)
return urlQueryItems.compactMap ({ $0.value })
}
//USE LIKE THIS
let saleActionURL = createSaleRequest(amount: 12.00, tipAmount: 2.00, clientTransactionId: nil, isvDetails: nil, numberOfInstallments: nil)
(UIApplication.shared.delegate as? AppDelegate)?.performInterAppRequest(request: saleActionURL)
Request example
Request sample:vivapayclient://pay/v1?callback=interapp-callback&merchantKey=SG23323424EXS3&appId=com.vivawallet.InterAppDemo&action=sale&amount=1200&tipAmount=200&withInstallments=false&show_receipt=false
Request sample for merchants registered in Greece(including AADE parameters):vivapayclient://pay/v1?callback=interapp-callback&merchantKey=SG23323424EXS3&appId=com.vivawallet.InterAppDemo&action=sale&amount=1200&tipAmount=200&withInstallments=false&show_receipt=false&aadeProviderId=999&aadeProviderSignatureData=AD33729F4ED749928AAFA00B90EE4EA91551BAC1;;20231204080313;1051;10000;2400;12400;POS_1&aadeProviderSignature=o0094r3Yk3KTqASLkW3evlDsnIg/ZAdUUf6UCXDtjqpI/dquzAT4WNX3yzS/GLciVNbT75H4pj8hLOV0EpHtzw==
Sale response
After executing a Sale transaction the ‘Viva.com Terminal’ application responds with a Sale Response result to indicate if the transaction has been approved or not.
The result is received as a URI in the callback activity.
The table below summarises the contents of an approved response.
Field | Description | Example |
---|---|---|
callback | The URI callback that will handle the result. | 'interapp-callback://result' |
status | The status of the transaction. | 'success' |
transactionEventId | The event ID code of the transaction. | 10075 (= PIN entry tries exceeded) |
bankId | The ID of card network | 'NET_EBNK' |
message | A string containing information about the transaction status. | 'Transaction successful' |
action | Sale transaction. | 'sale' |
clientTransactionId | The client transaction ID. | '12345678901234567890123456789012' |
amount | The amount in cents without any decimal digits. | '1200' = 12 euro |
tipAmount | How much of the amount in cents is considered as tip without any decimal digits. | '200' = 2 euro |
verificationMethod | The verification method used. Possible values: CHIP, CONTACTLESS, MAGNETIC, MANUAL ENTRY |
'CONTACTLESS' |
rrn | The Retrieval Reference Number of the transaction RRN. | '123456833121' |
cardType | The card type. | 'Debit Mastercard' |
transactionTypeId | Provides information about the type of transaction. For a full list of transaction types and their corresponding codes, please see the Transaction Types section. Please note: In case `transactionTypeId` is 60(IRIS Sale), 61(IRIS Refund) or 84(IRIS Void), `cardType` will be null. |
'4' |
accountNumber | The card number masked. Note that only the 6 first and the 4 last digits are provided. All other digits are masked with stars. | '537489******1831' |
referenceNumber | A number with up to 6 digits indicating the transaction's STAN (System Trace Audit Number). | '833121' |
authorisationCode | A 6-digit number indicating the transaction's Authorisation code provided by the host. | '690882' |
tid | A 12 character string indicating the terminal's TID number. | '16016684' |
orderCode | The order code. | '1091166300000136' |
shortOrderCode | The order code in short format. | '1091166300' |
installments | Number of card installments. | '10' |
transactionDate | The transaction date in ISO 8601 format. | '2019-09-13T12:14:19.8703452+03:00' |
transactionId | A unique identifier for the transaction. | 'a78e045c-49c3-4743-9071-f1e0ed71810c' |
appId | The application id that was used for the transaction. | A0000000041010 |
aadeTransactionId | An AADE-specific transaction ID. Format: Acquirer Unique code + RRN + Authorization code. Example: ‘116’ + ‘123456833121’ + ‘690882’ = '116123456833121690882' |
'116123456833121690882' |
Examples
A sale response result for an approved transaction looks as follows:
interapp-callback://result?transactionEventId=0&status=success&message=Transaction successful&action=sale&clientTransactionId=1234567890&amount=146&tipAmount=23&rrn=121343565787&verificationMethod=CHIP&cardType=Debit Mastercard&accountNumber=515876******4490&referenceNumber=174010&authorisationCode=174010&tid=16109900&orderCode=3050112220001919 &transactionDat=e=2023-06-13T11:22:33.1234567+03:00&transactionId=a12e1ba8-6153-7754-a6a8-e3d2654872c8&shortOrderCode=3050112220&sourceCode=6532
A sale response for a successful transaction using AADE parameters looks as follows:
interapp-callback://result?transactionEventId=0&status=success&message=Transaction successful&action=sale&clientTransactionId=1234567890&amount=146&tipAmount=23&rrn=121343565787&verificationMethod=CHIP&cardType=Debit Mastercard&accountNumber=515876******4490&referenceNumber=174010&authorisationCode=174010&tid=16109900&orderCode=3050112220001919 &transactionDat=e=2023-06-13T11:22:33.1234567+03:00&transactionId=a12e1ba8-6153-7754-a6a8-e3d2654872c8&shortOrderCode=3050112220&sourceCode=6532&aadeTransactionId=116407412859062859062
It is expected that certain transactions will fail for various reasons. A Sale response result for a failed transaction looks as follows:
interapp-callback://result?transactionEventId=10012&status=failure&message=Transaction%2520declined&action=sale&amount=101&orderCode=1092136112000136&shortOrderCode=1092136112&rrn=109210030077&tid=16000136&tipAmount=0&transactionDate=2021-04-02T13%253A26%253A09.158+0300
The structure of the message is the same as in the case of an approved transaction. Fields such as referenceNumber
and authorisationCode
may not have values since there is no STAN code available, nor an authorisation code.
Get Support
If you would like to integrate with Viva, or if you have any queries about our products and solutions, please see our Contact & Support page to see how we can help!