Skip to content

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: 2.3.130

Changes

Date Author 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.xx Added Transaction report request

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

  1. The POI must be able to listen for TCP/HTTP connections (i.e. the POI is the server).
  2. 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.
  3. The request/response protocol between the POS and the POI will be based on HTTP over TCP.
  4. 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.
  5. For the communication of POS and POI on the same device, it is possible to communicate using Android Intents.
  6. 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:

  1. MOCK - A token with this environment can be used only on MOCK application builds.
  2. MODEL - A token with this environment can be used on MODEL and MOCK application builds.
  3. 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. Requests are authorized with an API key obtained via the Dotypay Portal - every user can create (and delete) their own API key on their profile.

Authorization: ApiKey <apiKey>

Each request must also contain two additional headers:

  1. 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. In order for authorization to be successful, the API key provided in the Authorization header must belong to a user who has access to the specified device.

    X-Cloud-Identifier: 085c4fbf-b838-45c2-b648-92ffd0c9bd91

  2. 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.
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 in format object, which consists of three format items:
    • size (int): Text size. Default value is 18. Bigger texts, like amount value, should have their value around 26.
    • bold (boolean): true if the text should be printed in bold. false otherwise.
    • align (string): One of the following values: start, center, end.
  • twocolumns - The text should be formatted into two colums, defined in properties left and right. 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.

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

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:

  1. The state of the various modules of the POI Terminal POIStatus:

    1. 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.
    2. The status of the security module (cryptographic keys exchange): SecurityOKFlag.
    3. 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.
    4. The status of the communication module: CommunicationOKFlag.

    5. If requested, the state of the Acquirer Hosts HostStatus:
    6. The status of connectivity to the Host: IsReachableFlag.
    7. Additional data from the Acquirer in ProprietaryTags:
      1. If the communication is successful, HostResponseOK holds true.
      2. Additional acquirer message in HostResponseMessage.
  2. 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
              }
          }
      }
      
  3. 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. 1 or More combined SearchCriterias used to match transactions
  2. Optionaly a SearchOutputOrder (will be implemented in future)
  3. 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:

  1. The result of the Transaction Report request: Response.
  2. The total number of transactions matching the search criterias ReportFullSize
  3. The index BlockStart of the first transaction
  4. The index BlockStop of the last transaction
  5. 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.

Supported opeartors: EQ, LT, LE, GT, GE.

  • 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"
                              }
                          ]
                      }
                  ]
              }
      
          }
        }
      }
      
  • 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"
                          }
                      },
                      {
                          "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.

  • Request (application/json)

    • 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
              },
              {
                  "POIID": "POITERM1",
                  "BusinessId": "25292498",
                  "MerchantName": "Smart software s.r.o.",
                  "Currency": "CZK",
                  "SmartTipsAvailable": true
              }
          ]
      }