Sale request
An overview of the Sale request message for iOS.
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 | |
| fiscalisationData | Required data for fiscalisation invoicing services provided by Viva For more information details about the syntax of this parameter click here. |
For more information details about an example of this parameter click here. | |
| 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:
Please note, Moto payments are not supported if the sale request is done with ISV credentials. |
|
| 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 Provider (ΥΠΑΗΕΣ) 999 |
|
| 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_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?,
fiscalisationData: String?,
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&paymentMethod=CardPresent
var urlQueryItems: [URLQueryItem] = []
// Amount
let amountQueryItem = URLQueryItem(
name: "amount",
value: NSDecimalNumber(decimal: amount * 100).intValue.description
)
urlQueryItems.append(amountQueryItem)
// Tip amount
if let tipAmount = tipAmount {
let tipQueryItem = URLQueryItem(
name: "tipAmount",
value: NSDecimalNumber(decimal: tipAmount * 100).intValue.description
)
urlQueryItems.append(tipQueryItem)
}
// Payment method
let paymentMethodQueryItem = URLQueryItem(
name: "paymentMethod",
value: "CardPresent"
)
urlQueryItems.append(paymentMethodQueryItem)
// Client transaction ID
if let clientTransactionId = clientTransactionId,
!clientTransactionId.isEmpty {
let transactionIdQueryItem = URLQueryItem(
name: "clientTransactionId",
value: clientTransactionId
)
urlQueryItems.append(transactionIdQueryItem)
}
// Installments
var hasInstallments = false
if let preferredInstallments = numberOfInstallments,
preferredInstallments > 1 {
let preferredInstallmentsQueryItem = URLQueryItem(
name: "preferredInstallments",
value: preferredInstallments.description
)
urlQueryItems.append(preferredInstallmentsQueryItem)
hasInstallments = true
}
let hasInstallmentsQueryItem = URLQueryItem(
name: "withInstallments",
value: hasInstallments.description
)
urlQueryItems.append(hasInstallmentsQueryItem)
// Fiscalisation data
// Already encoded String - do not encode again.
if let fiscalisationData = fiscalisationData,
!fiscalisationData.isEmpty {
let fiscalisationDataQueryItem = URLQueryItem(
name: "fiscalisationData",
value: fiscalisationData
)
urlQueryItems.append(fiscalisationDataQueryItem)
}
// ISV
let isvQueryItems = getISVQueryItems(
isvDetails: isvDetails
)
urlQueryItems.append(contentsOf: isvQueryItems)
// Show receipt
let showReceipt = UserDefaults.standard.value(
forKey: "show_receipt"
) as? Bool ?? true
let showReceiptQueryItem = URLQueryItem(
name: "show_receipt",
value: showReceipt.description
)
urlQueryItems.append(showReceiptQueryItem)
// Show transaction result
let showTransactionResult = UserDefaults.standard.value(
forKey: "show_transaction_result"
) as? Bool ?? true
let showTransactionResultQueryItem = URLQueryItem(
name: "show_transaction_result",
value: showTransactionResult.description
)
urlQueryItems.append(showTransactionResultQueryItem)
// AADE
let aadeQueryItems = getAADEQueryItems(
aadeDetails: aadeDetails,
aadeProviderId: aadeProviderId,
aadeProviderSignature: aadeProviderSignature
)
urlQueryItems.append(contentsOf: aadeQueryItems)
// Add query parameters
saleActionURL.append(
queryItems: urlQueryItems
)
return saleActionURL
}
private func getISVQueryItems(
isvDetails: ISVDetails?
) -> [URLQueryItem] {
guard let isvDetails = isvDetails else {
return []
}
var urlQueryItems: [URLQueryItem] = []
let isvClientIdQueryItem = URLQueryItem(
name: "ISV_clientId",
value: isvDetails.clientId
)
let isvAmountQueryItem = URLQueryItem(
name: "ISV_amount",
value: NSDecimalNumber(
decimal: isvDetails.amount * 100
).intValue.description
)
let isvClientSecretQueryItem = URLQueryItem(
name: "ISV_clientSecret",
value: isvDetails.clientSecret
)
urlQueryItems.append(isvClientIdQueryItem)
urlQueryItems.append(isvAmountQueryItem)
urlQueryItems.append(isvClientSecretQueryItem)
if let sourceCode = isvDetails.sourceCode,
!sourceCode.isEmpty {
let isvSourceCodeQueryItem = URLQueryItem(
name: "ISV_sourceCode",
value: sourceCode
)
urlQueryItems.append(isvSourceCodeQueryItem)
}
return urlQueryItems
}
private func getAADEQueryItems(
aadeDetails: AADEDetails?,
aadeProviderId: Int?,
aadeProviderSignature: String?
) -> [URLQueryItem] {
guard let aadeProviderId = aadeProviderId else {
return []
}
var urlQueryItems: [URLQueryItem] = []
let aadeProviderIdQueryItem = URLQueryItem(
name: "aadeProviderId",
value: aadeProviderId.description
)
urlQueryItems.append(aadeProviderIdQueryItem)
if let aadeDetails = aadeDetails {
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)
}
if let aadeProviderSignature = aadeProviderSignature,
!aadeProviderSignature.isEmpty {
let aadeProviderSignatureQueryItem = URLQueryItem(
name: "aadeProviderSignature",
value: aadeProviderSignature
)
urlQueryItems.append(aadeProviderSignatureQueryItem)
}
return urlQueryItems
}
// USE LIKE THIS
let saleActionURL = createSaleRequest(
amount: 12.00,
tipAmount: 2.00,
clientTransactionId: nil,
isvDetails: nil,
numberOfInstallments: nil,
fiscalisationData: "YOUR_ENCODED_FISCALISATION_DATA" // only for merchants using Viva fiscalisation services,
aadeDetails: nil,
aadeProviderId: nil,
aadeProviderSignature: 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 with Fiscalisation Data for Merchants Registered in Greece:vivapayclient://pay/v1?callback=interapp-callback&merchantKey=SG23323424EXS3&appId=com.vivawallet.InterAppDemo&action=sale&amount=1200&tipAmount=200&withInstallments=false&show_receipt=false&fiscalisationData=ewoidHJhbnNtaXNzaW9uSW5kaWNhdG9yIjogMCwKInNpZ25hdHVyZXMiOiBbCnsKImNhcHRpb24iOiAiU3RyaW5nIiwKImRhdGEiOiAiU3RyaW5nIiwKImZvcm1hdCI6IDAKfQpdCn0=
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&paymentMethod=CardPresent&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 |
| fiscalisationSigningDetails | Fiscalisation details for invoicing services provided by Viva | The format is base64 ewoidHJhbnNtaXNzaW9uSW5kaWNhdG9yIjogMCwKInNpZ25hdHVyZXMiOiBbCnsKImNhcHRpb24iOiAiU3RyaW5nIiwKImRhdGEiOiAiU3RyaW5nIiwKImZvcm1hdCI6IDAKfQpdCn0= |
| 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:
A sale response for a successful transaction using AADE parameters looks as follows:
A sale response for a successful transaction using fiscalisationData parameter looks as follows:
It is expected that certain transactions will fail for various reasons. A Sale response result for a failed transaction looks as follows:
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!