Dotypay - Payment Protocol
The purpose of this document is to provide the POS (ECR) with a single API to communicate with external POI devices. We use the Nexo standard as the API. This document describes the Nexo messages that is used in our solution. We do not copy here the entire Nexo standard spec. For further information you could refer to and learn the official Nexo document.
We prepared example requests for the Postman application, you can download them here.
Payment Protocol Version: 1 (based on Nexo protocol v3.1)
Dotypay version: 3.0.70
Changes
Date | Author | Dotypay Version | Description |
---|---|---|---|
06.04.2022 | PO | v2.3.40 | Added support for DNS-SD |
03.05.2022 | PO | v2.3.60 | Added SETTLEMENT_ERROR result code |
14.09.2022 | PO | v2.3.130 | Added Diagnosis request support |
24.01.2023 | PO | v2.4.70 | Added support for custom identifier |
30.03.2023 | PO | v2.5.20 | Added new proprietary tags for tips |
29.06.2023 | PO | v2.5.60 | Added Transaction report request |
19.02.2024 | PO | v2.5.70 | Added new auth token module and extended poitermlist parameter |
19.02.2024 | PO | v2.5.80 | Added new data to extended poitermlist response |
19.02.2024 | PO | v2.5.90 | Added new data to extended poitermlist response and receipt data to transaction report |
19.07.2024 | SK | v3.0.70 | Added Deferred Sale (Pre-Authorization) request documentation |
Overview
Glossary
Term | Description |
---|---|
POS | Point of Sale. This is the cash register (ECR), AKA Sale system. This term may refer to the hardware or the software of the POS. |
POI | Point of Interaction. This is the payment terminal, AKA PED. |
PED | PIN Entry Device. Same as POI. |
Nexo | The nexo Retailer protocol defines a set of interfaces between a card payment application and a retail point of sale system. |
JSON | JavaScript Object Notation. |
HTTP | HyperText Transfer Protocol. The Nexo messages will be sent using HTTP over TCP |
HTTPS | An extension of HTTP that is used for secure communication over a computer network |
POIID | A logical number that identifies the POI. |
TID | Terminal ID. This is a unique logical number of the payment terminal. TID will be used as the POIID. |
CNP | Card not present |
General Requirements and Limitations
- The POI must be able to listen for TCP/HTTP connections (i.e. the POI is the server).
- The POS is the client. It creates the TCP/HTTP connection to the POI and sends the request to the POI using HTTP over TCP. The POS keeps the TCP/HTTP connection open until it gets the response.
- The request/response protocol between the POS and the POI will be based on HTTP over TCP.
- The HTTP body will be of Nexo format. This document will focus on the Nexo messages that are sent in the HTTP body. For more information about Nexo, please refer to Nexo official specification.
- For the communication of POS and POI on the same device, it is possible to communicate using Android Intents.
- The POI communicates with POS through a HTTPS protocol with self-signed certificate. This certificate is used just to enable an encrypted communication, not to verify POI's identity.
Default values
Default port number for STPay is set to 7500
for production, test and mock release.
Please contact integrace@dotypay.com for mock device and token.
HTTP Format
Mandatory HTTP Request Headers
The following HTTP headers are mandatory:
Content-Type:application/json
Content-Length: <the length of the JSON request string (the HTTP body)>
The POS (ECR) may send more headers, but they will be ignored by the POI.
Authentication
In order to secure the NEXO calls, every request needs to be authorized and authenticated.
Authentication
Requests are authorized with a bearer token, which can be obtained through a POS certification process.
Each request must contain a header field with the token:
Authorization: Bearer <token>
Tokens have limited validity and they need to be periodically renewed. For development purposes, you can apply for a token, which will work on mockup devices.
Token environment
The token environment is bound to an application build type, which restricts its usage in certain application builds.
There are three environment tiers:
- MOCK - A token with this environment can be used only on MOCK application builds.
- MODEL - A token with this environment can be used on MODEL and MOCK application builds.
- PRODUCTION - This token can be used in every application build.
Token modules
Each token contains a set of modules, which authorizes the ECR to do certain actions.
- BASE module - Basic functionality. Allows Sale and Reversal transactions, TransactionStatusRequest, AbortRequest and PoiTermList.
- PRINTS module - Allows printing on ECR. If the token doesn't contain this module, printing will always be done on the POI.
- SETTLEMENT module - Allows creating X and Z reports (reconciliations) from ECR.
- REFUND module - Allows Refund transactions.
- STATUS module - Allows to proceed handshake with aquirer.
- TRANSACTION_LIST module - Allows to get transaction list (filtered by date).
- PAIRING module - Allows to start POS pairing procedure.
The Certification process
Every third party integrator can apply for a MOCK
environment token.
With this token, they implement all the functions needed to certify their application.
Then Dotypay assigns them a token for the MODEL
environment, which they embed into their application.
Application with this token type will be used during the certification process in Dotypay.
If all required tests pass, Dotypay will issue a PRODUCTION
environment token to the integrator.
Authentication for cloud-based communication
When the cloud-terminal feature is enabled in POI configuration, POS can send request using cloud service on https://cloud-terminal.dotypay.com.
Each request must contain two headers:
-
X-Cloud-Identifier
to specify the device the request is meant for. This identifier can be created on a device's edit page on the Dotypay Portal. The identifier is a randomly generated UUID.X-Cloud-Identifier: 085c4fbf-b838-45c2-b648-92ffd0c9bd91
-
X-Terminal-Authorization
with the bearer token described above (see Authentication for versions 2.0 and newer).X-Terminal-Authorization: Bearer <token>
First request
If the POS runs on the same device as POI, it is recommended to check if the Nexo server is running. If the server is not running, you can start it programmatically using an Intent.
Request intent must target the launch intent for STPAY package (com.stpos.a8pos
).
PackageManager pm = activity.getPackageManager();
// throws an Exception if STPAY is not installed
pm.getPackageInfo("com.stpos.a8pos", PackageManager.GET_ACTIVITIES);
Intent intent = pm.getLaunchIntentForPackage("com.stpos.a8pos");
if (intent != null) {
intent.setFlags(0);
intent.putExtra("START_NEXO_SERVER", true);
activity.startActivityForResult(intent, REQUEST_CODE);
}
After STPAY starts the server, it will return back to the Activity, which sent the Intent.
DNS-SD Service
When the HTTPS interface is enabled, the device let's the local network know about its existence via DNS Service Discovery.
This service primarily serves the ECR to determine the address and port of the POI device if they have changed. The ECR identifies the terminal using a unique DeviceId, which it transmits as part of its service name.
The service type is _https._tcp.
, service name is DotypayNexoServer/DeviceId
.
For information about the DeviceId, please see the POI Terminal List (/poitermlist
request) section.
This feature is available from version 2.3.40
.
Intent based communication
If the POS (ECR) is running on the same device as POI, the POS can call POI’s activity and receive result after the request is complete without any HTTP communication whatsoever.
First, the POS should check if the Payment Application is running.
- If the Payment App isn’t running, the request intent should be the launch intent for it’s package (
com.stpos.a8pos
). - If the Payment App is running, the request intent should target it’s Main View (
com.stpos.a8pos.main.MainView
).
The Intent should be send with flags 0
.
Request parameters
The request data in NEXO format must be placed as String Extra under key NEXO_REQUEST
.
From version 1.4.0
are mandatory String extras USERNAME
and PASSWORD
, which will be checked when the request Intent arrives.
These credentials are the same for both HTTP and Intent communication.
Response parameters
After the request is completed, the activity finishes and the result will be delivered through the onActivityResult()
method in your Activity.
The NEXO response payload will be available under the NEXO_RESPONSE
key.
Nexo message structure
Nexo Message Structure consists of 3 main components:
1. a message envelope - SaleToPOIRequest/SaleToPOIResponse
, depends if request or response
2. a message header - contains request metadata, consists of 7 elements
3. a message body - holds different content for each MessageType and MessageCategory
Request structure
{
"SaleToPOIRequest": {
"MessageHeader": {
...header data...
}
...body...
}
}
POIID value in MessageHeader will be checked by the POI to identify the request recipient. If the POIID in the message header is not identical to the POIID as it is defined in the POI, then the POI will not accept the request and it will return an error. In the response, the POI will put its POIID in this tag (even if the POS sent the wrong POIID).
ECR Print in request
Each request, which may print a receipt, can contain ProprietaryTags
element with an ECRPrint
attribute in it.
If the ECR has a PRINTS
module in its token, the ECR is allowed to tell the POI, who will print the receipt.
If the ECR doesn't have the module mentioned above, its usage is forbidden.
When ECRPrint in the request isn't used, the terminal will use it's own configuration to tell the ECR whether it must print the receipt or not.
Response structure
{
"ResultCode": 0,
"SaleToPOIResponse": {
"MessageHeader": {
...header data...
}
...body...
}
}
Each response object contains a result code in a ResultCode
field to identify the request result.
Result code list
Name | Code | Description |
---|---|---|
UNDEFINED | -1 | Unclassified result. |
OK | 0 | Success. |
UNAUTHORIZED | 100 | The authorization failed. Check your credentials. |
INVALID_CONTENT_TYPE | 101 | Request content-type has to be 'application/json'. |
INVALID_JSON | 102 | The request JSON is not valid. |
EMPTY_BODY | 103 | The request is empty. |
UNKNOWN_REQUEST | 104 | The request is not valid or this request method is not implemented yet. |
MANDATORY_DATA_MISSING | 105 | The request is missing required data. |
ANOTHER_REQUEST_BEING_PROCESSED | 106 | The terminal is processing another transaction. Retry the request later. |
HTTP_METHOD_NOT_ALLOWED | 107 | This HTTP method is not allowed. |
REQUEST_TYPE_NOT_ALLOWED | 108 | The request type is not allowed on this terminal. |
WRONG_TID | 109 | Terminal ID (TID, POIID) in the request doesn't correspond with the TID of this payment terminal. |
CURRENCY_NOT_ALLOWED | 110 | Payment terminal does not allow to make transactions in this currency. |
INVALID_AMOUNT | 111 | The request amount should be greater than zero. |
TIMEOUT | 200 | Request timeout. |
NOT_FOUND | 201 | Transaction with provided parameters was not found. |
NO_REVERSIBLE_TRANSACTION_FOUND | 202 | Cannot reverse the transaction. |
TRANSACTION_IS_NOT_REVERSIBLE | 203 | Cannot reverse the transaction. |
CANCELED_BY_USER | 204 | The transaction was canceled by user. |
CARD_READ_ERROR | 205 | The provided card could not be read. |
ABORTED | 206 | The request was aborted externally. |
CARD_READ_TIMEOUT | 207 | The card was not read in time. |
NO_CONNECTION | 208 | The payment terminal cannot connect to the payment server. |
NOT_ABORTABLE | 209 | Transaction with given parameters cannot be aborted. |
PIN_TIMEOUT | 210 | The PIN hasn't been entered in time. |
PIN_ERROR | 211 | An irrecoverable error happened while entering a PIN. |
PIN_KEY_NOT_SYNCHRONIZED | 212 | Recoverable error indicating that a PIN key is not synchronized, preventing a new transaction from starting. The application automatically attempts to synchronize the key. Synchronization requires an internet connection and valid configuration. If this error persists despite an internet connection, manual intervention from support is required. |
HOST_REFUSED_GENERIC | 300 | Transaction was refused. |
WRONG_PIN | 301 | Transaction was refused because the the customer PIN was incorrect. |
EMPTY_HOST_RESPONSE | 302 | Payment authorization switch returned an empty answer. |
TECHNICAL_REVERSAL | 303 | The request was sent to payment switch and the result could not be read. The transaction was successfully canceled afterwards. |
PAYMENT_SWITCH_COMMUNICATION_ERROR | 304 | The request was sent to payment switch and the result could not be read. The transaction was not canceled due to another error. If you receive this result code, please call the support to verify the transaction result. |
PLACE_CALL | 305 | The transaction requires a phone authorization. The staff member must call the authorization centre to complete the transaction. |
SIGNATURE_NOT_VERIFIED | 306 | The transaction was successful and required a signature verification, which failed. The transaction was reversed afterwards. |
CALL_SUPPORT | 307 | The transaction was sent to the payment switch and no response was received back. The staff member must call the technical support to discover the transaction result. |
EMV_DECLINED | 308 | The transaction was declined by EMV kernel. If the transaction was successfully approved by the host, the transaction was reversed. |
SETTLEMENT_ERROR | 309 | Settlement has been sent to the acquirer and the result was not delivered, or it ended up with an error. The staff member should be prompted to try the request again and, if it also fails, to call a technical support. |
Concurrency
Only one request can be processed at the time.
If there are more concurrent requests, only the first one will be processed and the other ones will return busy response (result code 106
).
The same scenario is applied if the terminal processes a transaction locally.
ECR Print in response
The ECR must print the receipt if the ECRPrint
attribute in ProprietaryTags
element is set to true
.
If the ECR's token doesn't have the PRINTS
module, ECRPrint
will always be false
.
The location of ProprietaryTags
varies depending on the type of Request (see individual Response examples).
The ECRPrint is available in the app versions 1.4.0
and higher.
Nexo standards definies the location of the receipt data inside PaymentReceipt structure, which is located inside the particular response object (see the examples below).
For some reponse objects (ie. ReconciliationResponse) Nexo standards doesn't define PaymentReceipt structure,
so the Receipt data will be located inside ProprietaryTags
element.
Dotypay receipt format
If ECRPrint in Proprietary tags is set to true
, the response object also contains the receipt data in Dotypay format
and the ECR is obliged to print the receipt.
outputContent.OutputFormat
determines the data format.
Currently supported format is Dotypay
(from version 2.1.0).
The DotypayData tag contains an array of receipt lines.
Each line is a JSON object with predefined format.
Line format types
- text - The basic text to print. It is in the
text
property. The format is defined informat
object, which consists of three format items:- size (int): Text size. Default value is
18
. Bigger texts, like amount value, should have their value around26
. - bold (boolean):
true
if the text should be printed in bold.false
otherwise. - align (string): One of the following values:
start
,center
,end
.
- size (int): Text size. Default value is
- twocolumns - The text should be formatted into two colums, defined in properties
left
andright
. Each column is text type with it's own format. - division - A horizontal division line for separating content on the receipt.
- image - An image. If the image is from enumerated list, it will contain it's enumerated value, so the POS doesn't have to parse the binary data every time. The fields in the image line are:
- data (string): BASE64 encoded bmp data. Flags for the encoding are NO_WRAP and NO_PADDING.
- enumValue (string). Supported values are:
- CLESS_LOGO: Logo for contactless transaction
The sample output is in the Sale response.
Mockup
Mockup version of STPAY app is shown as STPAY MOCK
in the laucher.
This version of the app doesn't communicate with any server, thus the implementator can use production cards to test the transactions with.
Because the card data are not being verified online, transaction result is being set based on the requested amount.
If the reqested amount is:
- greater or equal to 1000: transaction is declined,
- greater or equal to 555 and less than 556: result is
PLACE CALL
, - greater or equal to 666 and less than 667: result is
TECHNICAL REVERSAL FAIL
, - greater or equal to 110 and less than 121: result contains additional food card data.
Supported Transaction Types [/]
Sale [POST]
A request combining the Auth and Completion transactions that instructs the Gateway to perform both actions,
one after the other:
query the bank for authorization and, upon approval, immediately complete the transaction.
In Nexo, the Sale is done by using "PaymentType": "Normal"
ProprietaryTags
in PaymentTransaction
is optional.
The POS can set the tipping options by setting the value of AskForTip
in ProprietaryTags
.
If the value is missing, the customer will be asked for a tip based on the POI configuration.
If the user was asked for a tip, the POI performs the payment transaction for the RequestedAmount increased by the value of
tip amount, and the TipAmount
will be present in the response if the whole payment is authorised as following:
AmountsResp.AuthorizedAmount = AmountsReq.RequestedAmount + AmountsResp.TipAmount
The POS can also request the variable symbol prompt by setting the value of AskForVariableSymbol
in ProprietaryTags
to true
.
The VariableSymbol
value overrides the AskForVariableSymbol
- if the VariableSymbol
is present, the POI will use the provided VS and won't ask the user for it.
Terminal also supports custom transaction identifier, which is an alphanumeric alternative for the variable symbol with one difference: it is not sent
to the acquirer.
The POS can request the custom identifier prompt by setting the value of AskForCustomIdentifier
in ProprietaryTags
to true
.
The CustomIdentifier
value overrides the AskForCustomIdentifier
- if the CustomIdentifier
is present, the POI will use the provided identifier and won't ask the user for it.
When RequireTipConfirmation
proprietary tag is set to true
, smart tip selection must be confirmed by pressing the "Next" button. Default value is false
.
If null
, terminal settings will be used.
When EnterTipAsTargetAmount
proprietary tag is set to true
, the user should enter tip as a target amount (base amount incl. tip), false
to enter just the tip.
If null
, terminal settings will be used.
When ForceCustomTip
proprietary tag is set to true
, the terminal will force entering the tip manually, even if the smart tips are enabled.
Amounts specified in the AmountsReq
object must have a maximum of 7 integer digits and 2 fraction digits.
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Request", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456" }, "PaymentRequest": { "PaymentData": { "PaymentType": "Normal" }, "PaymentTransaction": { "AmountsReq": { "Currency": "CZK", "RequestedAmount": 10 }, "ProprietaryTags": { "AskForTip": true, "VariableSymbol": "123123", "CustomIdentifier": "ABCD123", "AskForVariableSymbol": false, "ECRPrint": true, "RequireTipConfirmation": false, "EnterTipAsTargetAmount": false, "ForceCustomTip": false } }, "SaleData": { "SaleTransactionID": { "TimeStamp": "2020-04-19T14:20:00+0100", "TransactionID": "12345678-abcd-abcd-abcd-123456789abc" } } } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "ResultCode": 0, "SaleToPOIResponse": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456" }, "PaymentResponse": { "PaymentData": { "PaymentType": "Normal" }, "PaymentReceipt": { "documentQualifier": "saleReceipt", "integratedPrintFlag": true, "outputContent": { "OutputFormat": "Dotypay", "DotypayData": [ { "format": { "align": "start", "bold": false, "size": 18 }, "text": "Basic text", "type": "text" }, { "type": "division" }, { "left": { "format": { "align": "start", "bold": false, "size": 18 }, "text": "Left column text", "type": "text" }, "right": { "format": { "align": "end", "bold": false, "size": 18 }, "text": "Right column text", "type": "text" }, "type": "twocolumns" } ] }, "requiredSignatureFlag": false } "PaymentResult": { "AmountsResp": { "AuthorizedAmount": 11.0, "TipAmount": 1.0, "Currency": "CZK" }, "PaymentInstrumentData": { "CardData": { "MaskedPan": "53xx-xxxx-xxxx-1234" } }, "ProprietaryTags": { "Aid": "A0000000041010", "ApplicationName": "DEBIT MASTERCARD", "AuthorizationCode": "123456", "Brand": "MASTER", "CardExpiration": "20220731", "CardPresentationMethod": "CLESS", "CustomIdentifier": "ABCD123", "ECRPrint": true, "ReceiptDate": "2020-04-24T14:20:11+02:00", "SequenceNumber": "1234567890", "SignatureRequired": false, "TerminalId": "POITerm1 ", "VariableSymbol": "123123", "VerifiedByDevice": false, } }, "POIData": { "POITransactionID": { "TimeStamp": "2020-04-24T14:20:11+02:00", "TransactionID": "79fe58f3-511f-4964-9e63-91609ae02273" } }, "Response": { "Result": "Success" } } } }
-
Reversal [POST]
A request initiated by the merchant, Technical Support, or Risk department, instructing the Gateway to cancel (delete) the last transaction before end of day. The reversed transaction can either be a Completion, Sale or Refund. The reversal transaction enables you to cancel an erroneous or problematic transaction before it is completed.
In Nexo, it is done by using "MessageCategory": "Reversal"
in the message header.
Original transaction will be identified by data sent in OriginalPOITransaction.POITransactionID
field.
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest" : { "MessageHeader" : { "MessageCategory" : "Reversal", "MessageClass" : "Service", "MessageType" : "Request", "POIID" : "POITerm1", "ProtocolVersion" : "3.1", "SaleID" : "POS_ID_1234", "ServiceID" : "12345678" }, "ReversalRequest" : { "OriginalPOITransaction" : { "POITransactionID": { "TimeStamp": "2020-04-24T14:20:11+02:00", "TransactionID": "79fe58f3-511f-4964-9e63-91609ae02273" } }, "ReversalReason" : "MerchantCancel", "ProprietaryTags": { "ECRPrint": true } } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "ResultCode": 0, "SaleToPOIResponse": { "MessageHeader": { "MessageCategory": "Reversal", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "12345678" }, "ReversalResponse": { "PaymentReceipt": { "documentQualifier": "saleReceipt", "integratedPrintFlag": true, "outputContent": { "DotypayData": [ { "format": { "align": "start", "bold": false, "size": 24 }, "text": "Receipt data in Dotypay format", "type": "text" } ], "OutputFormat": "Dotypay" }, "requiredSignatureFlag": false }, "POIData": { "POITransactionID": { "TimeStamp": "2020-04-24T14:30:45+02:00", "TransactionID": "766b894f-4512-40ec-8505-82e13c795b0d" } }, "Response": { "Result": "Success" } } } }
-
Refund [POST]
A request instructing the Gateway to refund a previously completed transaction to the consumer.
In Nexo, the refund is done by using "PaymentType": "Refund"
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Request", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456789" }, "PaymentRequest": { "PaymentData": { "PaymentType": "Refund" }, "PaymentTransaction": { "AmountsReq": { "Currency": "CZK", "RequestedAmount": 10.00 }, "OriginalPOITransaction": { "POITransactionID": { "TimeStamp": "2020-04-24T15:57:48+02:00", "TransactionID": "bfb7fab0-e777-416f-9d87-ab4065da01cc" } }, "ProprietaryTags": { "ECRPrint": true } }, "SaleData": { "SaleTransactionID": { "TransactionID": "12345", "TimeStamp": "2020-04-24T15:59:00+0100" } } } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "ResultCode": 0, "SaleToPOIResponse": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456789" }, "PaymentResponse": { "PaymentData": { "PaymentType": "Refund" }, "PaymentReceipt": { "documentQualifier": "saleReceipt", "integratedPrintFlag": true, "outputContent": { "DotypayData": [ { "format": { "align": "start", "bold": false, "size": 24 }, "text": "Receipt data in Dotypay format", "type": "text" } ], "OutputFormat": "Dotypay" }, "requiredSignatureFlag": false }, "PaymentResult": { "AmountsResp": { "AuthorizedAmount": 10.0, "Currency": "CZK" }, "PaymentInstrumentData": { "CardData": { "MaskedPan": "53xx-xxxx-xxxx-1234" } }, "ProprietaryTags": { "Aid": "A0000000041010", "ApplicationName": "DEBIT MASTERCARD", "AuthorizationCode": "123456", "Brand": "MASTER", "CardExpiration": "20220731", "CardPresentationMethod": "CLESS", "ECRPrint": false, "ReceiptDate": "2020-04-24T15:59:24+02:00", "SequenceNumber": "1234567890", "SignatureRequired": false, "TerminalId": "POITerm1 ", "VerifiedByDevice": false } }, "POIData": { "POITransactionID": { "TimeStamp": "2020-04-24T15:59:24+02:00", "TransactionID": "f21ba5ef-ed98-4aff-a184-08866707cfc0" } }, "Response": { "Result": "Success" } } } }
-
Deferred Sale - Opening a Pre-Authorization [POST]
Pre-Authorization, referred to as Deferred Sale payment in the Nexo protocol specification, is used to separate the payment into two steps: - Before the service consumption or goods delivery, to get the payment authorization for a requested maximum amount. - At the end of the consumption or delivery, to complete the payment transaction with the actual amount.
To complete the first step, the ECR must call a PaymentRequest
as described in the "Sale" section but change the PaymentType
to OneTimeReservation
.
In order to further manipulate the pre-authorization (e.g., complete or cancel it), one must use the identifier returned in SaleToPOIResponse.PaymentResponse.POIData.POITransactionID.TransactionID
to reference it:
- Calling a ReversalRequest
to cancel the pre-authorization.
- Calling a PaymentRequest
with the PaymentType
set to Completion
as described in the "Deferred Sale - Completing a Pre-Authorization" request section.
The following restrictions apply to pre-authorizations:
- An opened pre-authorization is valid for 30 days and cannot be completed after this duration passes.
- The MinimumAmountToDeliver
parameter isn't currently supported in Dotypay.
- The following parameters from the Nexo protocol specification are currently unsupported in Dotypay and should not be used as a reference to the transaction in the POS:
- SaleTransactionID
- MerchantCategoryCode
- SaleItem
- LoyaltyAccountID
It is recommended to use the ServiceID
parameter as a reference to the transaction in POS.
When a pre-authorization is successfully opened, the amount in AuthorizedAmount
in PaymentResponse
will always match the amount requested in the PaymentRequest
from the original request.
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Request", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456" }, "PaymentRequest": { "PaymentData": { "PaymentType": "OneTimeReservation" }, "PaymentTransaction": { "AmountsReq": { "Currency": "CZK", "RequestedAmount": 10 } }, "SaleData": { "SaleTransactionID": { "TimeStamp": "2024-07-10T09:10:21+02:00", "TransactionID": "12345678-abcd-abcd-abcd-123456789abc" } } } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "SaleToPOIResponse": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456" }, "PaymentResponse": { "PaymentData": { "PaymentType": "OneTimeReservation" }, "PaymentResult": { "AmountsResp": { "AuthorizedAmount": 10.00, "Currency": "CZK" }, "PaymentInstrumentData": { "CardData": { "MaskedPan": "12xx-xxxx-xxxx-3456" } }, "PaymentType": "OneTimeReservation", "ProprietaryTags": { "Aid": "A0000000041010", "ApplicationName": "DEBIT MASTERCARD", "AuthorizationCode": "MOCK-624968", "Brand": "MASTER", "CardExpiration": "3210", "CardPresentationMethod": "CLESS", "ECRPrint": false, "ReceiptDate": "2024-07-10T09:10:23+02:00", "SequenceNumber": "1234567890", "SignatureRequired": false, "TerminalId": "AG542135", "TransactionStatus": "APPROVED", "VerifiedByDevice": false } }, "POIData": { "POITransactionID": { "TimeStamp": "2024-07-10T09:10:23+02:00", "TransactionID": "a535c05ecaea729721d7af882f31c00127e3ea44" } }, "Response": { "Result": "Success" } } }, "ResultCode": 0 }
-
Deferred Sale - Completing a Pre-Authorization [POST]
At the end of the consumption or delivery, where a pre-authorization was previously opened, the pre-authorization should be completed.
To complete an opened pre-authorization, the ECR must call a PaymentRequest
with the PaymentType
parameter set to Completion
, specifying the final amount in RequestedAmount
.
As a reference to the pre-authorization the ECR wishes to complete, the identifier SaleToPOIResponse.PaymentResponse.POIData.POITransactionID.TransactionID
from the pre-authorization response should be used.
The reference should be put into the SaleToPOIRequest.PaymentTransaction.OriginalPOITransaction.POITransactionID.TransactionID
request parameter.
Any unclaimed funds that were previously pre-authorized will be returned to the cardholder.
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Request", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456" }, "PaymentRequest": { "PaymentData": { "PaymentType": "Completion" }, "PaymentTransaction": { "AmountsReq": { "Currency": "CZK", "RequestedAmount": 5 }, "OriginalPOITransaction": { "POITransactionID": { "TimeStamp": "2024-07-10T13:38:48+02:00", "TransactionID": "a535c05ecaea729721d7af882f31c00127e3ea44" } } } } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "SaleToPOIResponse": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456" }, "PaymentResponse": { "PaymentData": { "PaymentType": "Completion" }, "PaymentResult": { "AmountsResp": { "AuthorizedAmount": 5.00, "Currency": "CZK" }, "PaymentInstrumentData": { "CardData": { "MaskedPan": "12xx-xxxx-xxxx-3456" } }, "PaymentType": "Completion", "ProprietaryTags": { "ApplicationName": "DEBIT MASTERCARD", "AuthorizationCode": "MOCK-480241", "CardPresentationMethod": "NONE", "ECRPrint": false, "ReceiptDate": "2024-07-10T11:01:16+02:00", "SequenceNumber": "1234567890", "SignatureRequired": false, "TerminalId": "AG542135", "TransactionStatus": "COMPLETED", "VerifiedByDevice": false } }, "POIData": { "POITransactionID": { "TimeStamp": "2024-07-10T11:01:16+02:00", "TransactionID": "a535c05ecaea729721d7af882f31c00127e3ea44" } }, "Response": { "Result": "Success" } } }, "ResultCode": 0 }
-
Transaction Status Request [POST]
The POS can recover the final status of a payment when the POS didn't receive the payment response from the POI.
A TransactionStatusRequest is an error recovery mechanism.
If the response of the payment request does not arrive within the predefined time limit,
you can retrieve the final status of the transaction.
Because the response didn't arrive, the POS cannot use the POI TransactionID because it doesn't know it.
So the POS will use the ServiceID
, SaleID
and MessageCategory
from previously sent MessageHeader
.
POI will return a unique transaction from combination of ServiceID
, SaleID
and MessageCategory
from MessageReference
sent in the Body of the request.
If the POI won't find exactly one transaction, an error will be returned.
Result code of the previous transaction is located in TransactionStatusResponse
.
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest": { "MessageHeader": { "MessageCategory": "TransactionStatus", "MessageClass": "Service", "MessageType": "Request", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "1234567" }, "TransactionStatusRequest": { "MessageReference": { "MessageCategory": "Payment", "SaleID": "POS_ID_1234", "ServiceID": "1234567" } } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "ResultCode": 0, "SaleToPOIResponse": { "MessageHeader": { "MessageCategory": "TransactionStatus", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "1234567" }, "TransactionStatusResponse": { "ResultCode": 0, "RepeatedMessageResponse": { "MessageHeader": { "MessageCategory": "Payment", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "123456" }, "RepeatedResponseMessageBody": { "PaymentResponse": { "PaymentData": { "PaymentType": "Normal" }, "PaymentReceipt": { "documentQualifier": "saleReceipt", "integratedPrintFlag": true, "outputContent": { "OutputFormat": "Dotypay", "DotypayData": [ { "format": { "align": "start", "bold": false, "size": 18 }, "text": "Basic text", "type": "text" }, { "type": "division" }, { "left": { "format": { "align": "start", "bold": false, "size": 18 }, "text": "Left column text", "type": "text" }, "right": { "format": { "align": "end", "bold": false, "size": 18 }, "text": "Right column text", "type": "text" }, "type": "twocolumns" } ] }, "requiredSignatureFlag": false }, "PaymentResult": { "AmountsResp": { "AuthorizedAmount": 10.0, "Currency": "CZK" }, "PaymentInstrumentData": { "CardData": { "MaskedPan": "53xx-xxxx-xxxx-1234" } }, "ProprietaryTags": { "Aid": "A0000000041010", "ApplicationName": "DEBIT MASTERCARD", "AuthorizationCode": "123456", "Brand": "MASTER", "CardExpiration": "20220731", "CardPresentationMethod": "CLESS", "ReceiptDate": "2020-04-24T14:20:10+02:00", "SequenceNumber": "1234567890", "SignatureRequired": false, "TerminalId": "POITerm1 ", "VerifiedByDevice": false } }, "POIData": { "POITransactionID": { "TimeStamp": "2020-04-24T14:20:10+02:00", "TransactionID": "79fe58f3-511f-4964-9e63-91609ae02273" } }, "Response": { "Result": "Success" } } } }, "Response": { "Result": "Success" } } } }
-
Reconciliation Request [POST]
The reconciliation request is used to close the sale interval on the POI (Z Report) or calculate the subtotals (X Report).
The Reconciliation request message body is ReconciliationRequest
and contains the ReconciliationType field, which determines the report type:
-
SaleReconciliation
: Reconciliation of the current reconciliation period, without any closing nor synchronisation with Acquirer reconciliations. (X report) -
AcquirerSynchronisation
: Reconciliation and closure of the current period, with synchronisation of reconciliations between the POI and the Acquirer. (Z report)
ProprietaryTags
in AcquirerSynchronisation
request may contain optional text note, which will be printed on the receipt.
This note will be repeated in the response.
The response contains data of transaction debit and credit counters and the terminal currency.
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest": { "MessageHeader": { "MessageCategory": "Reconciliation", "MessageClass": "Service", "MessageType": "Request", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "1234567" }, "ReconciliationRequest": { "ReconciliationType": "AcquirerSynchronisation", "ProprietaryTags": { "ECRPrint": true, "Note": "Custom note to identify this reconciliation" } } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "SaleToPOIResponse": { "MessageHeader": { "MessageCategory": "Reconciliation", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "1234567" }, "ReconciliationResponse": { "POIReconciliationID": 1, "ProprietaryTags": { "ECRPrint": true, "Note": "Custom note to identify this reconciliation", "ReceiptData": [ { "format": { "align": "start", "bold": false, "size": 24 }, "text": "Receipt data in Dotypay format", "type": "text" } ] }, "ReconciliationType": "AcquirerSynchronisation", "TransactionTotals": [ { "PaymentCurrency": "CZK", "PaymentTotals": [ { "TransactionAmount": 123.25, "TransactionCount": 2, "TransactionType": "Credit" }, { "TransactionAmount": 2535.98, "TransactionCount": 10, "TransactionType": "Debit" } ] } ], "Response": { "Result": "Success" } } }, "ResultCode": 0 }
-
Abort Request [POST]
The Abort message allows to halt and prematurely terminate the processing of the currently processed message. This request is most commonly used when a processing of a message is taking too much time. At the moment only the Payment Request message can be aborted.
The POI will make an attempt to abort the processing of a message identified by the combination of the following attributes: ServiceID
, SaleID
and MessageCategory
from MessageReference
sent in the Body of the request.
If any of these attributes is missing then the request is not processed and an Event Notification message with the attribute EventToNotify
set to Reject
is sent as a response. Reason of the abortion should be located in the attribute AbortReason
of the AbortRequest
object.
Attributes SaleID
and POIID
in the MessageReference
object must match the SaleID
and POIID
attributes present in the message header of the Abort Request message otherwise an Event Notification message with an attribute EventToNotify
set to Reject
is sent as a response.
If the referenced message cannot be aborted (e.g., it has already been sent to the issuer) a simple response with result code set to NOT_ABORTABLE
is sent and the referenced message is not aborted.
If the referenced message can be aborted then a simple response with result code set to OK
is sent and the POI aborts the ongoing transaction. A message with an attribute ErrorCondition
set to Aborted
, attribute Result
set to Failure
and attribute AdditionalResponse
containing the reason of abortion is sent as a response to the sender of the aborted Payment Request.
However, if the referenced message to be aborted has already been processed, an Event Notification message is sent as a response with the attribute EventToNotify
set to CompletedMessage
.
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest": { "MessageHeader": { "MessageCategory": "Abort", "MessageClass": "Service", "MessageType": "Request", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "1234567", "POIID": "POITerm1" }, "AbortRequest": { "MessageReference": { "MessageCategory": "Payment", "SaleID": "POS_ID_1234", "ServiceID": "1234567", "POIID": "POITerm1" }, "AbortReason": "The processing of the message is taking too long." } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "ResultCode": 0, }
-
Diagnosis Request [POST]
The diagnosis request is used to discover status of the POI terminal.
If the Diagnosis request contains HostDiagnosisFlag
set to false
or absent,
the Diagnostic response does not contain any HostStatus
data structure.
If the Diagnosis request has HostDiagnosisFlag
set to true
,
the POI tests the communication with the acquirer and the Diagnostic response must contain a HostStatus
data structure.
The Diagnosis response message body DiagnosisResponse, contains the following information:
-
The state of the various modules of the POI Terminal
POIStatus
:- The overall status of the POI Terminal:
GlobalStatus
. Possible values:OK
- The POI is ready to receive and process a request.Busy
- The POI Terminal cannot process a request because another processing is in progress.Maintenance
- The POI is in maintenance processing.Unreachable
- The POI is unreachable or not responding.
- The status of the security module (cryptographic keys exchange):
SecurityOKFlag
. -
The status of the printer:
PrinterStatus
. Possible values:OK
- The printer is operational.PaperLow
- The printer is operational but paper roll is almost empty.NoPaper
- Paper roll is empty, an operator must insert a new paper roll.PaperJam
- An operator must remove the paper jam manually.OutOfOrder
- The printer is out of order.
-
The status of the communication module:
CommunicationOKFlag
. - If requested, the state of the Acquirer Hosts
HostStatus
: - The status of connectivity to the Host:
IsReachableFlag
. - Additional data from the Acquirer in
ProprietaryTags
:- If the communication is successful,
HostResponseOK
holdstrue
. - Additional acquirer message in
HostResponseMessage
.
- If the communication is successful,
- The overall status of the POI Terminal:
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest": { "MessageHeader": { "MessageCategory": "Diagnosis", "MessageClass": "Service", "MessageType": "Request", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "1234567" }, "DiagnosisRequest": { "HostDiagnosisFlag": true } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "SaleToPOIResponse": { "DiagnosisResponse": { "HostStatus": { "IsReachableFlag": true, "ProprietaryTags": { "HostResponseMessage": "acquirer response message", "HostResponseOK": true } }, "POIStatus": { "CommunicationOKFlag": true, "GlobalStatus": "OK", "PrinterStatusType": "OK", "SecurityOKFlag": true } } }, "ResultCode": 0 }
-
Transaction Report Request [POST]
The Transaction Report Messages implement the possibility for the Sale system to request to the POI system a report on a list of transactions.
The request contains search criteria parameters to select which transactions will be included in the report.
The TransactionReport request message body TransactionReportRequest, contains the following information:
- 1 or More combined SearchCriterias used to match transactions
- Optionaly a SearchOutputOrder (will be implemented in future)
- Optionaly the index BlockStart of the first transaction and BlockStop of the last transaction
The Transaction Report response message body TransactionReportResponse, contains the following information:
- The result of the Transaction Report request: Response.
- The total number of transactions matching the search criterias ReportFullSize
- The index BlockStart of the first transaction
- The index BlockStop of the last transaction
- List of Transaction Report containing one Transaction Report for each transaction matching the Search criterias. This list may be partial according to requested block.
Supported search criteria targets: CREATION_DATE
, UUID
, MASKED_PAN
and SERVICE_ID
.
SERVICE_ID
is supported from version 2.5.120 onwards.
Supported opeartors: EQ
, LT
, LE
, GT
, GE
.
Starting with version 2.5.90
, support for ProprietaryTags.IncludePaymentReceipts
is added.
When IncludePaymentReceipts
is set to true
, transactions will contain their receipt data.
Default value is false
.
-
Request (application/json)
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb... Content-Length: <calculated>
-
Body
{ "SaleToPOIRequest" : { "MessageHeader" : { "MessageCategory" : "TransactionReport", "MessageClass" : "Service", "MessageType" : "Request", "POIID" : "POITerm1", "ProtocolVersion" : "3.1", "SaleID" : "POS_ID_1234", "ServiceID" : "1234567" }, "TransactionReportRequest" : { "BlockStart": 0, "BlockStop": 2, "DescendingOrder": true, "SearchCriterias": { "SearchOR": [ { "SearchAND": [ { "Target": "CREATION_DATE", "Operator": "GT", "Value": "2023-06-28T11:00:00" }, { "Target": "CREATION_DATE", "Operator": "LT", "Value": "2023-06-28T11:07:00" } ] } ] }, "ProprietaryTags": { "IncludePaymentReceipts": true } } } }
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "SaleToPOIResponse": { "MessageHeader": { "MessageCategory": "TransactionReport", "MessageClass": "Service", "MessageType": "Response", "POIID": "POITerm1", "ProtocolVersion": "3.1", "SaleID": "POS_ID_1234", "ServiceID": "1234567" }, "TransactionReportResponse": { "BlockStart": 0, "BlockStop": 2, "ReportFullSize": 3, "TransactionReport": [ { "PaymentResult": { "AmountsResp": { "AuthorizedAmount": 56.00, "Currency": "CZK" }, "PaymentInstrumentData": { "CardData": { "MaskedPan": "53xx-xxxx-xxxx-4405" } }, "ProprietaryTags": { "Aid": "A0000000041010", "ApplicationName": "DEBIT MASTERCARD", "Brand": "MASTER", "CardExpiration": "2507", "CardPresentationMethod": "CLESS", "ECRPrint": false, "SequenceNumber": "1234567890", "SignatureRequired": false, "TerminalId": "TS011", "VerifiedByDevice": false } }, "POIData": { "POITransactionID": { "TransactionID": "4f70fd0905ccc5580b00ed6ce13b0b31f0aea545" } }, "Response": { "Result": "Success" }, "PaymentReceipt": { "documentQualifier": "saleReceipt", "isIntegratedPrintFlag": true, "isRequiredSignatureFlag": false, "outputContent": { "DotypayData": [ { "format": { "align": "start", "bold": false, "size": 18 }, "text": "Receipt data...", "type": "text" }, { "type": "division" } ], "OutputFormat": "Dotypay" } } }, { "PaymentResult": { "AmountsResp": { "AuthorizedAmount": 56.00, "Currency": "CZK" }, "PaymentInstrumentData": { "CardData": { "MaskedPan": "53xx-xxxx-xxxx-4405" } }, "ProprietaryTags": { "Aid": "A0000000041010", "ApplicationName": "DEBIT MASTERCARD", "AuthorizationCode": "MOCK-917180", "Brand": "MASTER", "CardExpiration": "2507", "CardPresentationMethod": "CLESS", "CustomIdentifier": "jbvb", "ECRPrint": false, "ReceiptDate": "2023-06-28T11:06:38+02:00", "SequenceNumber": "1234567890", "SignatureRequired": false, "TerminalId": "TS011", "VariableSymbol": "005", "VerifiedByDevice": false } }, "POIData": { "POITransactionID": { "TimeStamp": "2023-06-28T11:06:38+02:00", "TransactionID": "a223dbbe365f8c3f02a3c50ea0e842d9951d8b03" } }, "Response": { "ErrorCondition": "Refusal", "Result": "Failure" } } ] } }, "ResultCode": 0 }
-
Protocol extensions [/poitermlist]
POI Terminal List [GET]
A request to discover the available POIIDs on current terminal.
It returns a POI Terminal list, which contains a list of available terminals on the device.
The caller then uses this POIID in the MessageHeader
object to identify the terminal,
which is communicating with.
The first record of POI Terminal list contains information about the proprietor of the physical device. POS systems could use this record as a fallback in pairing procedure (e.g. when POIID can't be found by BusinessID and Currency).
Starting with version 2.3.40, the response also contains a DeviceId
field, which uniquely identifies the device among others.
This identifier is being broadcasted via DNS-Service Discovery.
Starting with version 2.5.20, the response also contains SmartTipsAvailable
field, which holds true
if the terminal supports smart tip selection.
Starting with version 2.5.60, the app supports extended
parameter, which allows extended terminal information retrieval.
If the extended
parameter value is equal to true
, response will contain a AdditionalData
structure.
branchId
, merchantId
, CustomIdentifierCaption
(v2.5.80 and newer), customIdentifierForbiddenCharacters
(v2.5.90 and newer) and DisplayName
(v2.5.80 and newer) may be null
.
-
Request (application/json)
-
Parameters
- extended (boolean) - Whether to retrieve extended information about terminal. Defaults to
false
.
- extended (boolean) - Whether to retrieve extended information about terminal. Defaults to
-
Headers
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlb...
-
-
Response 200 (application/json)
-
Headers
-
Body
{ "ResultCode": 0, "DeviceId": "ABCDE12345", "POITerminalList": [ { "POIID": "POITERM2", "BusinessId": "25599051", "MerchantName": "Dotypay s.r.o.", "Currency": "EUR", "SmartTipsAvailable": false, "AdditionalData": { "BranchId": "123456", "CustomIdentifierCaption": "Enter custom id", "CustomIdentifierForbiddenCharacters": "", "DisplayName": "Terminal 2", "MerchantId": "654321", "ParserVariableSymbolFromCustomIdentifier": false, "QrPaymentEnabled": true, "VariableSymbolAllowed": false } }, { "POIID": "POITERM1", "BusinessId": "25292498", "MerchantName": "Smart software s.r.o.", "Currency": "CZK", "SmartTipsAvailable": true, "AdditionalData": { "BranchId": "234567", "CustomIdentifierCaption": "", "CustomIdentifierForbiddenCharacters": ",+[]", "DisplayName": "Terminal 1", "MerchantId": "765432", "ParserVariableSymbolFromCustomIdentifier": true, "QrPaymentEnabled": true, "VariableSymbolAllowed": true } } ] }
-