NAV Navbar
Shell C# Python 3.6
  • Introduction
  • Core Payments
  • Food & Beverage
  • API Specification
  • Value Added Applications
  • Appendix
  • Document Version
  • Introduction

    The 'Linkly Cloud' is a system developed by Linkly as a hosted payment integration system, where the POS and PIN pad connect securely to our systems, enabling clients to use our systems without requiring our software to be installed in-house. This allows a POS and PIN pad to be completely independent of each other and for the PIN pad to connect to the customer's internet connection instead of to the POS via serial or USB port. The Linkly Cloud REST API is an interface developed by Linkly to interface to our cloud-hosted EFT Clients in a clean, modern, web standards-compliant way. To use the Linkly Cloud REST API the POS must also use the Linkly Cloud product. There is no REST interface for EFT-Clients installed in-house.

    The advantages of this system are:

    Start Developing

    Technical Requirements

    Accounts and Resources

    Development requires an account in the Linkly Cloud sandbox environment and the Linkly Virtual PIN pad that simulates a bank PIN pad.

    Please direct any questions on the Linkly Cloud REST API to [email protected]

    Cloud PIN pad Pairing

    Whether you choose to use a hardware PIN pad or our Virtual PIN pad, you will first need to pair the PIN pad. PIN pad pairing refers to the process of using a Linkly Cloud username, password and temporary pairing code to connect the PIN pad to an account on our hosted back-end services. The pairing process generates a secret which allows the POS to initiate transactions on that specific PIN pad. See Authentication for details.

    An example of the basic PIN pad pairing process is below:

    1. Obtain a Cloud EFT Client username and password from Linkly for either Sandbox or Production (depending on whether you have a test or production PIN pad, respectively).
    2. Plug the PIN pad in and connect to the Internet via cable or Wi-fi depending upon the EFTPOS hardware.
    3. Set the PIN pad up to connect to the Linkly cloud. Each bank may have different configuration settings.
    4. Once connected, the PIN pad will display a temporary 'pair code'
    5. The POS should now send a 'pairing request' using the username, password, and PIN pad 'pair code' from the PIN pad
    6. The response to the 'pairing request' is a secret which should be stored securely by the POS. This secret does not expire, and will be valid until the account password changes, or the PIN pad is paired to another POS.
    7. The POS can now do a sale:
      • Get a REST authentication token using the secret. If the POS already has a token from a previous session it may use it until ExpirySeconds is up, or alternatively a new token may be requested for each transaction.
      • Check that a valid token is received
      • Do a sale using the specification below
      • Wait for the transaction response, either as an HTTP response to the original transaction request (async=false), or as a postback from the API (async=true)

    Example Pairing UI

    Pairing UI

    Authentication

    The Linkly Cloud REST API uses a two-step authentication process.

    Step 1 - PIN pad pairing request

    The POS pairs with a PIN pad using the Linkly Cloud username, password, and a temporary 'pair code' which is displayed on the PIN pad. This is a one-time request which returns a non-expiring secret. This secret remains valid until either the Linkly Cloud password changes, or another POS pairs with the same PIN pad.

    Step 2 - Auth Token request

    The POS uses the secret obtained from step 1 to perform a token request to the Linkly Cloud authentication service. The result of this request is a token which can be used to perform a transaction on the PIN pad.

    PIN pad pairing request

    PIN pad pairing request

    # replace <<username>>, and <<password>> with your own credentials
    # replace <<paircode>> with the paircode displayed on the PIN pad
    curl "https://auth.sandbox.cloud.pceftpos.com/v1/pairing/cloudpos" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Accept: application/json' \
      -d '{
            "username": "<<username>>",
            "password": "<<password>>",
            "paircode": "<<paircode>>"
          }'
    
    // replace <<username>>, and <<password>> with your own credentials
    // replace <<paircode>> with the paircode displayed on the PIN pad
    var requestContent = new
    {
        Username = "<<username>>",
        Password = "<<password>>",
        PairCode = "<<paircode>>"
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, "https://auth.sandbox.cloud.pceftpos.com/v1/pairing/cloudpos")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import requests; # http://python-requests.org
    
    # replace <<username>>, and <<password>> with your own credentials
    # replace <<paircode>> with the paircode displayed on the PIN pad
    request_payload = {
        'username': '<<username>>',
        'password': '<<password>>',
        'pairCode': '<<paircode>>'
    }
    response = requests.post('https://auth.sandbox.cloud.pceftpos.com/v1/pairing/cloudpos', json=request_payload)
    response_payload = response.json()
    

    URI Path

    Production:

    POST https://auth.cloud.pceftpos.com/v1/pairing/cloudpos

    Development Sandbox environment:

    POST https://auth.sandbox.cloud.pceftpos.com/v1/pairing/cloudpos

    Headers

    Parameter Value
    Content-Type application/json
    Accept application/json

    Request Body

    Example PIN pad pairing request object

    {
        "username": "123456789",
        "password": "QWERTY",
        "pairCode": "09876"
    }
    
    Field KeyName Required Description
    Username Yes The Linkly Cloud username
    Password Yes The Linkly Cloud password
    PairCode Yes The pair code displayed on the PIN pad in "pairing" mode

    Status Codes

    Code Description Required action
    200 Pairing was successful. The response object will contain the secret. The POS store the secret securely.
    401 The username, password, or paircode was invalid. Re-check the Cloud username, try resetting the Cloud password
    400 Invalid request. Correct the request and try again.
    408 Request Timeout. This should be rare: a transient error has occurred, possibly due to server overloading. Wait a few seconds and attempt the request again. If the problem persists, contact Linkly Support.
    500-599 A server error has occurred. Wait a few seconds and attempt the request again. If the problem persists, contact Linkly Support.

    PIN pad Pairing Response

    Example PIN pad Pairing response object

    {
        "secret":"R6pqwt5ThZkjDXa7WA9aAgXUcAyGjX6a"
    }
    
    Field KeyName Description
    secret The non-expiring secret the POS uses to request an auth token

    Auth Token Request

    Token request

    # replace <<secret>> with the secret returned from the cloud pairing process
    # replace <<posName>> and <<posVersion>> with the name and version of your POS
    # replace <<posId>> with a unique UUID v4 which identifies your POS instance
    # replace <<posVendorId>> with the unique UUID v4 which identifies your POS product
    curl "https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Accept: application/json' \
      -d '{
            "secret": "<<username>>",
            "posName": "<<posName>>",
            "posVersion": "<<posVersion>>",
            "posId": "<<posId>>",
            "posVendorId": "<<posVendorId>>"
          }'
    
    // replace <<secret>> with the secret returned from the cloud pairing process
    // replace <<posName>> and <<posVersion>> with the name and version of your POS
    // replace <<posId>> with a unique UUID v4 that identifies your POS instance
    // replace <<posVendorId>> with the unique UUID v4 which identifies your POS product
    var requestContent = new
    {
        Secret = "<<secret>>",
        PosName = "<<posName>>",
        PosVersion = "<<posVersion>>",
        PosId = "<<posId>>",
        PosVendorId = "<<posVendorId>>",
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, "https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import requests; # http://python-requests.org
    
    # replace <<secret>> with the secret returned from the cloud pairing process
    # replace <<posName>> and <<posVersion>> with the name and version of your POS
    # replace <<posId>> with a unique UUID v4 that identifies your POS instance
    # replace <<posVendorId>> with the unique UUID v4 which identifies your POS product
    request_payload = {
        'secret': '<<secret>>',
        'posName': '<<posName>>',
        'posVersion': '<<posVersion>>',
        'posId': '<<posId>>',
        'posVendorId': '<<posVendorId>>',
    }
    response = requests.post('https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos', json=request_payload)
    response_payload = response.json()
    

    URI Path

    Production:

    POST https://auth.cloud.pceftpos.com/v1/tokens/cloudpos

    Development Sandbox environment:

    POST https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos

    Headers

    Parameter Value
    Content-Type application/json
    Accept application/json

    Request Body

    Example token request object

    {
        "secret": "R6pqwt5ThZkjDXa7WA9aAgXUcAyGjX6a",
        "posName": "Test POS",
        "posVersion": "12.6.80.17",
        "posId": "3e7f5001-58a3-43fa-9129-6e84a7b4f2a0",
        "posVendorId": "a256b7ec-709d-4c7d-8ffe-57cc7ca1fd22",
    }
    
    Field KeyName Required Description
    Secret Yes The secret returned from the cloud pairing process
    PosName Yes The name of the POS requesting the token
    PosVersion Yes The version of the POS requesting the token
    PosId Yes A unique UUID v4 which identifies the POS instance. This value is generated by the POS as a part of the POS deployment settings. e.g. Two registers at the same merchant should supply two different PosId values
    PosVendorId Yes A unique UUID v4 which identifies the POS POS product. This value can be hard coded into the build of the POS. e.g. All merchants using the same POS product should supply the same posVendorId value

    Status Codes

    Code Description Required action
    200 Authorisation was successful. The response object will contain the auth token. Store and maintain the token based on the expirySeconds property.
    401 The secret was invalid. You will need to perform the PIN pad pairing process again
    400 Invalid request. Correct the request and try again.
    408 Request Timeout. This should be rare: a transient error has occurred, possibly due to server overloading. Wait a few seconds and attempt the request again. If the problem persists, contact Linkly Support.
    500-599 A server error has occurred. Wait a few seconds and attempt the request again. If the problem persists, contact Linkly Support.

    Auth Response

    Example token response object

    {
        "token":"x2MUks9vdreTp8aHjfcULkQxURurcRCb",
        "expirySeconds":86400 
    }
    
    Field KeyName Description
    token The token to user for authentication.
    expirySeconds The number of seconds until the token expires.

    Using the token

    The Bearer token is added to each request as an HTTP header with the keyword Bearer as shown below:

    Authorization: Bearer <token goes here>

    When a token is received from the Linkly Authentication service it is the responsibility of the POS to securely store and manage the lifetime of that token and request a new one when the old token has expired.

    The expirySeconds is returned with each token response. This value indicates the number of seconds until the token expires. The POS can use this value to calculate and record the local expiry date and time.

    We recommend requesting a new token if it is due to expire within a few minutes of the request.

    The POS can request tokens as often as required, however if the POS requests a new token for each transaction or each request this will slow down transaction times. Be aware that requesting a new token does not currently cause existing valid tokens to be revoked, but this may change in future without warning.

    During an async transaction, be aware that if the token expires mid-transaction it will need to be renewed if the POS needs to send a sendkey request to the PIN pad.

    C# example: checks to see if the token has expired

    class TokenResponse
    {
        public string Token { get; set; }
        public double ExpiryMinutes {
            get
            {
                return (ExpiryDateTime - DateTime.UtcNow).TotalMinutes;
            }
            set
            {
                ExpiryDateTime = DateTime.UtcNow.AddMinutes(value);
            }
        }
        public DateTime ExpiryDateTime { get; set; } = DateTime.UtcNow;
    }
    
    TokenResponse token = null;
    
    private async Task<T> PostRequestAsync<T>(Uri baseUri, Guid sessionId, string type, EFTRequest request, bool async)
    {
        var httpClient = GetHttpClient(); // Get a pre-constucted HttpClient from some repository, factory, or static instance
        if (token == null || token.ExpiryDateTime < DateTime.UtcNow.AddSeconds(10)) // notice 10 second offset
        {
            token = await GetTokenAsync(appSettings.PinpadUsername, appSettings.PinpadPassword, appSettings.PinpadPairCode);
    
            if (token == null || string.IsNullOrWhiteSpace(token.Token))
            {
                throw new Exception("Failed to get valid token");
            }
        }
    
        var uri = new Uri(baseUri, $"sessions/{sessionId}/{type}?async={async.ToString().ToLower()}");
    
        var request = new HttpRequestMessage() 
        {
            RequestUri = new Uri("http://www.someURI.com"),
            Method = HttpMethod.Post,
        };
        request.Headers.Accept.Add(new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token.Token);
        HttpContent content = new StringContent(JsonConvert.SerializeObject(request), UTF8Encoding.UTF8, "application/json");
    
        var response = await httpClient.SendAsync(request);
    
        if (response.IsSuccessStatusCode)
        {
            if (async)
            {
                return default(T); // nothing to return, now it's time to wait for the postbacks
            }
            return JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
        }
        else             
        {
            switch (response.StatusCode)
            {
                case System.Net.HttpStatusCode.Unauthorized:
                    throw new UnauthorizedAccessException("Looks like the username, password or pair code is no longer valid, or your account has been disabled. Try re-pairing the PIN pad or resetting the password.");
                case System.Net.HttpStatusCode.NotFound:
                    throw new Exception("Ooops, this shouldn't happen.  Check that your base URI and type are correct.");
                case System.Net.HttpStatusCode.BadRequest:
                    throw new Exception("That request wasn't valid! Inspect the response message to see what's wrong.");
                default:
                    throw new Exception("Server error, timeout, PIN pad error, etc. Call GET /sessions/{id}/transaction to see the status of this transaction or try again later.");
            }
        }
    }
    

    Async vs Sync Mode

    The Linkly Cloud REST API works using one of the two following methods, synchronous and asynchronous. The mode is selected when POSTing a request by using the URI parameter async=false or async=true

    Synchronous

    Synchronous mode is the simplest and supports both POS Server to API or direct POS Client to API communication, however it is more limited in utility as the POS typically gets no feedback on progress of the EFT transaction until the result is returned at the end, indicating success or failure.

    1. If the POS doesn't have a valid authentication token it requests one from the Linkly Token Authentication service, using credentials provided by Linkly
    2. The POS sends its request to the API endpoint with the token in the header
    3. The operator completes the sale on the PIN pad while the POS waits for an HTTP response
    4. The POS receives a response with the result of the transaction

    When using Sync mode the Notification object is not required in the request, although if it is supplied the notifications can still be sent to a separate postback web service if required (e.g. for logging purposes).

    Client-to-Cloud API

    Linkly Cloud Synchronous API implemented directly from POS client to Linkly Cloud API.

    Synchronous Client-API

    Server-to-Cloud API

    Linkly Cloud Synchronous API implemented from POS server to Linkly Cloud API.

    Synchronous Server-API

    Asynchronous

    Asynchronous mode supports POS Server to API communication only, as postbacks to the POS need a publicly accessible Notification URI. We recommend where possible that POS developers use this method, as it provides a better user experience, more functionality (e.g. key presses from the POS and mid-transaction status notifications) and is closer to other Linkly implementations.

    1. If the POS doesn't have a valid authentication token it requests one from the Linkly Token Authentication service, using credentials provided by Linkly.
    2. The POS sends its request to the API endpoint with the token in the header. It receives a "202 Accepted" HTTP response if successful, and the transaction begins
    3. The Linkly Cloud REST API sends postback messages to the provided notification URI each time the PIN pad display changes and each time a receipt is generated. The operator proceeds with the sale
    4. The POS can optionally POST additional sendkey requests to the PIN pad (to respond to requests for user input) via the REST interface using a valid token and the same session ID used to initiate the transaction. Examples of sendkey requests include "OK", "Cancel", "Yes", etc.
    5. When the transaction is complete the API sends a postback message indicating transaction completion with the result of the transaction

    Server-to-Cloud API

    Linkly Cloud Asynchronous API implemented from POS server to Linkly Cloud API.

    ASynchronous Server-API

    API Requests

    Request URI

    The request URI is made up of 4 parts; the base endpoint, a sessionId, the type of request to make, and the async URI parameter.

    URI FORMAT

    Request Types
    transaction
    logon
    settlement
    status
    querycard
    configuremerchant
    reprintreceipt
    sendkey

    Production Endpoints

    For Authentication the POS should sends its token requests to:

    https://auth.cloud.pceftpos.com/v1/tokens/cloudpos

    The base request API endpoint is:

    https://rest.pos.cloud.pceftpos.com/v1/sessions

    Examples of complete production URIs:

    URI
    https://rest.pos.cloud.pceftpos.com/v1/sessions/c98433543a0d43eeba8f5876607f1df0/transaction?async=true
    https://rest.pos.cloud.pceftpos.com/v1/sessions/79e133ee3bc44339abfce86c93951193/logon?async=false
    https://rest.pos.cloud.pceftpos.com/v1/sessions/e6e2c68f217c469e977cddb56592f7ad/settlement?async=true
    https://rest.pos.cloud.pceftpos.com/v1/sessions/bc30254273d74b1dad95ef6426ee3892/status?async=false
    https://rest.pos.cloud.pceftpos.com/v1/sessions/5e833e504d124f4fb31954e76eab7691/querycard?async=true
    https://rest.pos.cloud.pceftpos.com/v1/sessions/795f214fbde645e8a7f7c8ae8dfba4f7/configuremerchant?async=true
    https://rest.pos.cloud.pceftpos.com/v1/sessions/1808c4ebc57a48fe8dba2a55f65b3c28/reprintreceipt?async=false
    https://rest.pos.cloud.pceftpos.com/v1/sessions/ba573b113af3577568546ecb327c0059/sendkey?async=true

    Development Endpoints

    For Authentication the POS should sends its token requests to:
    https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos

    The base request API endpoint is: https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/

    Examples of complete development URIs:

    URI
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/c98433543a0d43eeba8f5876607f1df0/transaction?async=false
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/79e133ee3bc44339abfce86c93951193/logon?async=false
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/e6e2c68f217c469e977cddb56592f7ad/settlement?async=false
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/bc30254273d74b1dad95ef6426ee3892/status?async=false
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/5e833e504d124f4fb31954e76eab7691/querycard?async=false
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/795f214fbde645e8a7f7c8ae8dfba4f7/configuremerchant?async=false
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/1808c4ebc57a48fe8dba2a55f65b3c28/reprintreceipt?async=false
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/ba573b113af3577568546ecb327c0059/sendkey?async=true

    Notifications

    Example notification request object

    {
        "Request": { },
        "Notification":{
            "Uri": "https://pos.example.com/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"  
        }
    }
    

    The Notification object is only required if the POS uses async mode.

    If a Notification object is provided as a part of the request, Linkly Cloud REST API will send information about the request such as displays, receipts and the transaction response to the endpoint specified by the POS in the Uri field of the notification object.

    The object is made up of two fields: Uri and AuthorizationHeader.

    Field KeyName Description
    Uri Contains the Uri to send the responses to (must be https)
    AuthorizationHeader (Optional) value to add for the authorization header

    When providing a Notification Uri the POS can include {{sessionid}} and {{type}} in its URI which will be replaced by the session Id of the request and the type of response received, respectively.

    Example:
    Uri: https://pos.example.com/{{sessionId}}/{{type}}

    POSTed with the session Id 12345678-90AB-CDEF-1234-1DECAFCOFFEE:
    https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/12345678-90ab-cdef-1234-1decafcoffee/transaction

    The API would send display responses for this transaction to https://pos.example.com/12345678-90ab-cdef-1234-1decafcoffee/display a transaction response would be https://pos.example.com/12345678-90ab-cdef-1234-1decafcoffee/transaction

    These fields are optional and can be used without the other, or as a part of the query string. For example:

    Error Recovery

    Error recovery only applies to the Transaction request and simply refers to performing a GET request to the API to request the Transaction Status, using the same sessionId as the original Transaction request.

    The POS must enter error recovery if, on POSTing a transaction request:

    In recovery the POS should use the same 'sessionId' as the original transaction to periodically call Transaction Status until one of the following HTTP Status codes is received:

    Any other HTTP status code (202, 408, 500-599) should mean the POS continues to retry. See Exponential Backoff for details and an example.

    Example

    1. You POST a transaction to https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/c98433543a0d43eeba8f5876607f1df0/transaction
    2. You receive an HTTP error 408 indicating that the request has timed out. This does not specify whether or not the transaction succeeded.
    3. You enter recovery mode and start polling GET https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/c98433543a0d43eeba8f5876607f1df0/transaction every few seconds.
    4. You receive an HTTP 202 each time indicating the transaction is still in progress.
    5. Eventually you receive an HTTP 200 with a valid transaction response. The transaction reponse object (not the HTTP Status code) indicates the financial success of the transaction.

    The error recovery can end when either:

    All other HTTP response codes indicate that, in one way or another, the POS should keep trying to GET the transaction response, as outlined below.

    Sync Mode Recovery

    The error recovery sequence diagrams for both client-to-cloud and server-to-cloud synchronous mode of communication is shown below.

    Client-to-Cloud error recovery

    Synchronous Client-API error recovery

    Server-to-Cloud error recovery

    Synchronous Server-API error recovery

    HTTP Response codes returned from Transaction Status.

    HTTP Code Description Required action
    200 OK - This will be accompanied by a valid response. The 'success' property in the response object indicates the financial status of the transaction. Inspect the response to check the result of the financial transaction (eg. Approved, Declined, Approve with signature, etc.)
    202 Accepted - The original transaction has been received but is not yet complete. Response body will be null. The POS should retry the GET request every 1-2 seconds for up to 3 minutes, or until another HTTP code is received.
    400 Invalid request - This error does NOT indicate success or failure of the original transaction, but rather that the GET request is badly formed. It is likely that the session Id is not a valid UUID. Do NOT retry this GET request, as it is incorrectly formed.
    401 Unauthorised - The token supplied is invalid. This error does NOT indicate success or failure of the original transaction. The POS should refresh the token and attempt the GET request again.
    404 Resource not found - Either the GET request URI is incorrect (the endpoint was not found) or the session Id requested was not found, hence the original transaction was not submitted successfully. So long as the Transaction Status URI is configured correctly, the POS can safely retry the original transaction with the same (or new) sessionId.
    408 Request Timeout - This should be rare: a transient error has occurred, possibly due to server overloading. The POS should retry the GET request every few seconds for up to 3 minutes, or until another code is received. Please use exponential backoff to avoid overloading the server further.
    500-599 A server error has occurred. The POS should continue to perform the GET request using exponential backoff to avoid overloading the server.

    Async Mode Recovery

    The POS must enter error recovery if no transaction response postback notifications are received from the Linkly Cloud within 3 minutes, even if all other responses (receipts/displays...) have been received.

    Asynchronous Server-API error recovery

    HTTP Response codes returned from Transaction Status.

    HTTP Code Description Required action
    200 OK - This will be accompanied by a valid response. The 'success' property in the response object indicates the financial success of the transaction. Inspect the response to check the result of the financial transaction (eg. Approved, Declined, Approve with signature, etc.)
    202 Accepted - The original transaction has been received but is not yet complete. Response body will be null. The POS should await the result in its notification postback, or retry the GET request every 1-2 seconds for up to 3 minutes or until another HTTP code is received.
    400 Invalid request - This error does NOT indicate success or failure of the original transaction, but rather that the GET request is badly formed. It is likely that the session Id is not a valid UUID. Do NOT retry this GET request, as it is incorrectly formed.
    401 Unauthorised - The token supplied is invalid. This error does NOT indicate success or failure of the original transaction. The POS should refresh the token and attempt the request again.
    404 Resource not found - Either the GET request URI is incorrect (the endpoint was not found) or the session Id requested was not found, hence the original transaction was not submitted successfully. So long as the Transaction Status URI is configured correctly, the POS can safely retry the original transaction with the same (or new) sessionId.
    408 Request Timeout - This should be rare: a transient error has occurred, possibly due to server overloading. The POS should retry the GET request every few seconds for up to 3 minutes, or until another code is received. Please use exponential backoff to avoid overloading the server further.
    500-599 A server error has occurred. The POS should continue to perform the GET request using exponential backoff to avoid overloading the server.

    Exponential backoff

    Exponential backoff is a technique used to reduce added strain on already overloaded servers, networks or infrastructure. It refers to the process of increasing the delay between each subsequent request, starting with a short delay and working up to a longer delay if the error condition continues. We request that if you get a response from our servers that may indicate overloading that you employ basic exponential backoff in your recovery attempts.

    In-depth example:

    1. You POST a transaction to https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/c98433543a0d43eeba8f5876607f1df0/transaction
    2. You receive an HTTP error 408 indicating that the request has timed out. This does not specify whether or not the transaction succeeded.
    3. You enter recovery mode and immediately try to GET the Transaction Status from https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/c98433543a0d43eeba8f5876607f1df0/transaction
    4. You receive another HTTP 408. You delay 1 second and try the GET request again (initial delayed attempt).
    5. You receive another HTTP 408. You delay 2 seconds and try the GET request again (backoff by doubling delay).
    6. You receive another HTTP 408. You delay 4 seconds and try the GET request again (backoff by doubling delay again).
    7. You receive an HTTP 404 error indicating that the original transaction was NOT SUCCESSFUL, ie. the sessionId was not found. You can now exit recovery mode and retry the original transaction, POSTing a transaction to https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/c98433543a0d43eeba8f5876607f1df0/transaction again.
    8. You receive an HTTP error 408 indicating that the request has timed out. This does not specify whether or not the transaction succeeded.
    9. You enter recovery mode again and immediately GET from https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/c98433543a0d43eeba8f5876607f1df0/transaction
    10. You receive another HTTP 408. You delay 1 second and try the GET request again.
    11. You receive another HTTP 408. You delay 2 seconds and try the GET request again.
    12. You receive an HTTP 202 indicating that the transaction is in progress. You keep trying the GET request every second, as long as you get a 202 (not an error condition, so backoff not required).
    13. You receive an HTTP 200 with a valid response indicating the financial success of the transaction.

    Core Payments

    Overview

    The Core Payments API offers a simple entry point for POS developers to send card payment transactions to Linkly supported PIN pads.

    Security

    All communications between the third-party provider and Linkly are encrypted with TLS 1.2. All communications between the lane and Linkly Cloud are encrypted with TLS 1.2.

    Supported Cipher Suites - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

    Minimum Requirements

    Below are the minimum requirements for a POS system to be considered for accreditation with the Linkly Core Payments API

    Transaction Types

    Management of merchant/bank functions

    Transactional Scenarios

    Error Handling

    Purchase

    The purchase transaction type allows the merchant to perform a sale, it uses the transaction request format.

    All refunds in the Core Payments API need to be matched to an original purchase. The POS will achieve this by storing the contents of the RFN PAD tag returned in the purchase response and, if a refund for this purchase is required, sending the contents of this field in the refund request.

    The 'REF' tag represents the transaction reference from the payment host. It will be printed on the receipt. The POS should record the 'REF' tag against the sale in the POS database to allow a transaction to be looked up from the receipt contents.

    Purchase Request

    Example transaction request object

    {
        "Request": 
        {
            "Merchant": "00",
            "TxnType": "P",
            "AmtPurchase": 100,     
            "TxnRef": "1234567890",
            "CurrencyCode": "AUD",      
            "CutReceipt": "0",
            "ReceiptAutoPrint": "0",
            "Application": "00",
            "PurchaseAnalysisData":
            {
                "OPR": "00766|test",
                "AMT": "0042000",
                "PCM": "0000"
            },
            "Basket": 
            {  
                "id": "t39kq18134553",  
                "amt": 2145,  
                "tax": 200,  
                "dis": 50,  
                "sur": 0,  
                "items": [{  
                    "id": "t39kq002",  
                    "sku": "k24086723",  
                    "qty": 2,  
                    "amt": 2145,  
                    "tax": 200,  
                    "dis": 50,  
                    "name": "XData USB Drive"  
                }]  
            } 
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Below are the fields from the transaction request that must be set for a purchase transaction.

    Field Name Type Required value Notes
    Merchant string(2) '00' Instructs the Linkly components to perform a card payment
    TxnType string(1) 'P' Purchase
    AmtPurchase number Variable Left zero filled, amount of sale in cents.
    TxnRef string(16) Variable The reference number to attach to the transaction. This will appear on the receipt.
    CurrencyCode string(3) Variable Code to indicate requested currency. e.g. 'AUD'
    CutReceipt string(1) Variable Indicates whether Linkly should cut receipts. Defaults to '0' (DontCut)
    ReceiptAutoPrint string(1) Variable Indicates if the POS is to receive receipt events. See ReceiptAutoPrint for available values
    Application string(2) '00' Instructs Linkly to perform a card payment
    PurchaseAnalysisData object Variable Extended fields. See PurchaseAnalysisData note below.
    Basket object Variable See basket section for details

    PurchaseAnalysisData

    Tag Name Type Notes Example
    OPR OperatorReference string(128) POS operator name and id. Format: ID|Name {"OPR": "66|test" }
    AMT TotalAmount string(9) Total amount of the entire sale in cents, not Tender amount {"AMT": "20000" } $200.00 total sale
    PCM POSCapabilitiesMatrix string(128) POS Capabilities Matrix. First byte = POS can scan Barcode {"PCM": "0000"}

    Purchase Response

    Example purchase response object

    {
        "SessionId": "dd250a0c81c202b66220d7379b338b8f",
        "ResponseType": "transaction",
        "Response": {
            "TxnType": "P",
            "Merchant": "00",
            "CardType": "AMEX CARD           ",
            "CardName": "05",
            "RRN": "123456789012",
            "DateSettlement": "2018-07-31T00:00:00",
            "AmtCash": 0,
            "AmtPurchase": 100,
            "AmtTip": 0,
            "AuthCode": 123456,
            "TxnRef": "1234567890      ",
            "Pan": "37601234567890      ",
            "DateExpiry": "4909",
            "Track2": "37601234567890=0949?,,S, YES, 05??????  ",
            "AccountType": "2",
            "TxnFlags": {
                "Offline": "1",
                "ReceiptPrinted": "0",
                "CardEntry": "S",
                "CommsMethod": "0",
                "Currency": "0",
                "PayPass": "0",
                "UndefinedFlag6": "0",
                "UndefinedFlag7": "0"
            },
            "BalanceReceived": false,
            "AvailableBalance": 0,
            "ClearedFundsBalance": 0,
            "Success": true,
            "ResponseCode": "00",
            "ResponseText": "APPROVED            ",
            "Date": "2018-07-31T16:14:40",
            "Catid": "12345678",
            "Caid": "0987654321     ",
            "Stan": 0,
            "PurchaseAnalysisData": {
              "RFN": "klujhadsc9ph87asd",
              "REF": "12345",
              "HRC": "ERR1",
              "HRT": "INVALID CARD"
            }
        }
    }
    

    The purchase response is in the format of the transaction response object, see the Transaction section for a detailed breakdown. The below tags are part of the PurchaseAnalysisData object in the response and are of critical importance to the core payments transactions.

    PurchaseAnalysisData

    Tag Name Type Notes Example
    RFN Reference Number string(128) Transaction Reference Number to be used in a refund, can contain additional information {"RFN":"klujhadsc9ph87asd"}
    REF Host reference Number string(32) Reference number to the sale from the provider systems, printed on receipt {"REF":"12345"}
    HRC Host Response Code string(64) Response code from the payment processor {"HRC":"ERR1"}
    HRT Host Response Text string(999) Response text from the payment processor {"HRT":"INVALID CARD"}

    Refund

    A refund transaction type allows the merchant to undo a sale, it uses the transaction request format. The POS must ensure that the correct 'RFN' Tag is sent when performing a refund.

    Refund Request

    {
        "Request": 
        {
            "Merchant": "00",
            "TxnType": "R",
            "AmtPurchase": 100,     
            "TxnRef": "1234567890",
            "CurrencyCode": "AUD",      
            "CutReceipt": "0",
            "ReceiptAutoPrint": "0",
            "App": "00",
            "PurchaseAnalysisData":
            {
                "RFN": "klujhadsc9ph87asd",
                "OPR": "00766|test",
                "AMT": "0042000",
                "PCM": "0000"
            }
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field Name Type Required value Notes
    Merchant string(2) '00' Instructs the Linkly components to perform a card payment
    TxnType string(1) 'R' Purchase
    AmtPurchase number Variable Left zero filled, amount of sale in cents.
    TxnRef string(16) Variable The reference number to attach to the transaction. This will appear on the receipt.
    CurrencyCode string(3) Variable Code to indicate requested currency. e.g. 'AUD'
    CutReceipt string(1) Variable Indicates whether Linkly should cut receipts. Defaults to '0' (DontCut)
    ReceiptAutoPrint string(1) Variable Indicates if the POS is to receive receipt events. See ReceiptAutoPrint for available values
    Application string(2) '00' Instructs Linkly to perform a card payment
    PurchaseAnalysisData object Variable Extended fields. See PurchaseAnalysisData note below.
    Basket object Variable See basket section for details

    PurchaseAnalysisData

    Tag Name Type Notes Example
    RFN Reference Number string(128) Reference Number from purchase request this refund is for {"RFN":"klujhadsc9ph87asd"}
    OPR OperatorReference string(128) POS operator name and id. Format: ID|Name {"OPR": "66|test" }
    AMT TotalAmount string(9) Total amount of the entire sale in cents, not Tender amount {"AMT": "20000" } $200.00 total sale
    PCM POSCapabilitiesMatrix string(128) POS Capabilities Matrix. First byte = POS can scan Barcode {"PCM": "0000"}

    Refund Response

    The refund response is in the format of the transaction response object, see the Transaction section for a detailed breakdown.

    PurchaseAnalysisData

    Tag Name Type Notes Example
    REF Host reference Number string(128) Reference number to the sale from the provider systems, printed on receipt {"REF":"12345"}
    HRC Host Response Code string(64) Response code from the payment processor {"HRC":"ERR1"}
    HRT Host Response Text string(999) Response text from the payment processor {"HRT":"INVALID CARD"}

    Management Functions

    The management functions allow the merchant to perform utility functions in addition to sales. The minimum requirements for these are; Reprint Receipt and Transaction Status

    Reprint Receipt

    The reprint receipt function allows for the retrieval/reprint of a financial receipt. The 'Merchant' field must be set to a unique 2-character code to specify the sale processor, this is returned in the purchase/refund response.

    Reprint Receipt Request

    Example reprint receipt request object

    {
        "Request": {
            "Merchant": "99",
            "ReceiptAutoPrint": "0",
            "ReprintType": "2"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field Name Type Required value Notes
    Merchant string(2) '00' Unique ID of third-party sale to fetch. Set to '99' to indicate generic reprint
    CutReceipt string(1) Variable Indicates whether Linkly should cut receipts. Defaults to '0' (DontCut)
    ReceiptAutoPrint string(1) Variable Indicates if the POS is to receive receipt events. See ReceiptAutoPrint for available values

    Reprint Receipt Response

    See Reprint Receipt Response Object for response format

    Transaction Status

    This function returns the last transaction event processed by Linkly. This function can be called by a POS to determine whether a transaction was successful or not following a power failure whilst an EFTPOS transaction was in progress, this is part of the error handling scenarios.

    See Transaction Status for request/response format

    Transactional Scenarios

    Partial/Split Payments

    Partial and split payments must be handled by the POS, when sending a purchase request the POS must set the 'AMT' Tag with the total amount of the entire sale the 'AmtPurchase' field should be set to the actual tender amount, in most cases these fields will be equal. When receiving a response the POS will receive the 'AmtPurchase' field set to the amount the sale was processed for if the POS receives an amount less than what was sent in the response it must continue to make payments until the entire tender is payed for.

    Example 1

    Example 2

    Error Handling

    The POS should implement error handling as outlined by the Error recovery section.

    Optional Functionality

    Custom Displays

    To implement custom display the POS must implement the async API and handle the Display Response notification and Send Key request

    If the POS is handling its own displays, it must implement the following:

    Input types:

    Example displays

    No keys enabled

    {
      "ResponseType": "display",
      "Response": {
        "NumberOfLines": 2,
        "LineLength": 20,
        "DisplayText": [
          "DISPLAY LINE 1", 
          "DISPLAY LINE 2"
        ]
      }
    }
    

    No keys enabled

    Cancel key enabled

    {
      "ResponseType": "display",
      "Response": {
        "NumberOfLines": 2,
        "LineLength": 20,
        "DisplayText": [
          "DISPLAY LINE 1", 
          "DISPLAY LINE 2"
        ],
        "CancelKeyFlag": true
      }
    }
    

    No keys enabled

    OK key enabled

    {
      "ResponseType": "display",
      "Response": {
        "NumberOfLines": 2,
        "LineLength": 20,
        "DisplayText": [
          "DISPLAY LINE 1", 
          "DISPLAY LINE 2"
        ],
        "OKKeyFlag": true
      }
    }
    

    No keys enabled

    Accept/decline keys enabled

    {
      "ResponseType": "display",
      "Response": {
        "NumberOfLines": 2,
        "LineLength": 20,
        "DisplayText": [
          "DISPLAY LINE 1", 
          "DISPLAY LINE 2"
        ],
        "AcceptYesKeyFlag": true,
        "DeclineNoKeyFlag": true
      }
    }
    

    No keys enabled

    Auth input enabled

    {
      "ResponseType": "display",
      "Response": {
        "NumberOfLines": 2,
        "LineLength": 20,
        "DisplayText": [
          "DISPLAY LINE 1", 
          "DISPLAY LINE 2"
        ],
        "CancelKeyFlag": true,
        "AuthoriseKeyFlag": true,
        "InputType": "1"
      }
    }
    

    No keys enabled

    POS Barcode Scanning

    This function allows the POS to scan a barcode instead of the PIN pad. The POS will receive a DisplayEvent and must answer with a SendKey; populating the DataEntry field this will be the Barcode for the sale. POS must set the PCM PAD tag's first byte to '1' to indicate it can support this functionality and wants to use it for the transactions.

    Transaction Request

    Perform a sale with the following Purchase Analysis Data Tag:

    Tag Name Tag Value Description Example
    PCM Flag array of functionality supported by POS POS Capabilities Matrix. First byte = POS can scan Barcode PCM0011

    This will cause the EFT-Client to send a DisplayEvent to the POS with the following properties:

    Display Event

    Field Name Length (characters) Description Example
    NumberOfLines 2 Number of lines of text '02' – two lines
    LineLength 2 Length of each line of text '20' line is 20 char long
    DisplayText 40 Text to display 'SCAN BARCODE'
    Cancel Key Flag 1 Indicates whether the CANCEL key can be pressed '0' = Disabled '1' = Enabled
    InputData Field Key 1 See 'Custom Displays' Section '7'
    OK Key Flag 1 Indicates whether the OK key can be pressed '0' = Disabled '1' = Enabled

    The POS must reply to the above display event with a SendKey Request as detailed below:

    Send Key Request

    Field Name Length (characters) Description Example
    Key 1 Indicated which key is to be pressed '0' for the CANCEL key '1' for the YES key '2' for the NO key '3' for the AUTH key '0' = CANCEL
    Data 60 Entry data collected by POS (the barcode) 209849083

    Linkly Basket

    The "basket" in the transaction request contains information about items in the transaction.

    Basket Command Header Fields

    {
     "id": "t39kq18134553",
     "amt": 17890,
     "tax": 1790,
     "dis": 1000,
     "sur": 358,
     "items": [...]
    }
    

    The basket header contains meta information about the basket, along with the id for the basket which is needed when sending a transaction with basket data, or when changing the basket.

    Name Required Description Format
    id Y A unique ID for the basket String, max 32
    amt Y Total price for the basket, in cents, including tax and discount, but excluding surcharge Integer
    tax Total tax for the basket, in cents Integer
    dis Total discount for the basket, in cents Integer
    sur Surcharge (e.g. for Credit Card), in cents Integer
    items Y Array of basket items JSON array

    Basket Command Item Fields

    Example basket item data object

    {  
        "id": "t39kq002",  
        "sku": "k24086723",  
        "qty": 2,  
        "amt": 2145,  
        "tax": 200,  
        "dis": 50,  
        "gtin": "831664397578",  
        "name": "XData USB Drive",  
        "desc": "24GB XData USB Drive, Red/Black",  
        "srl": "xd546467",  
        "img": "http://www.xdata.com/products/images/usb24_rb_1.jpg",  
        "link": "http://www.xdata.com/products.php&pid=usb24_rb",  
        "tag": "usb drive,storage"  
    }
    

    The basket items are required to have at least an id, sku, quantity, and price of the item included in the item data.
    Other fields can be used as desired by vendors.

    Name Required Description Format
    id Y A unique ID for the item String, max 32
    sku Y Merchant assigned SKU for the item String
    qty Y Quantity (number of units) Integer
    amt Y Individual unit price for the item, in cents, including tax and discount Integer
    tax Individual unit tax for the item, in cents Integer
    dis Individual unit discount for the item, in cents Integer
    ean The EAN (European Article Number) for the item String
    upc The UPC (Universal Product Code) for the item String
    gtin The GTIN (Global Trade Item Number) for the item String
    name A short name for the item String, max 24
    desc A longer description for the item String, max 255
    srl Serial code, or other identifying code, for the item String
    img URL to an image for the item String
    link URL to a product page for the item String
    tag Comma separated category or type information for the item (e.g. "food, confectionery”) String, max 64

    Basket Command Extended Item Fields

    {  
        "id": "t39kq001",  
        "sku": "s63787452",  
        "qty": 1,  
        "amt": 1995,  
        "weight": "2kg"  
    }
    

    In additional to the required and optional fields, an item may also include one or more extended fields for use by specific third parties. Extended fields are simply included along with the standard fields for the item.
    The example opposite includes "weight”, with a value of "2kg”, as an extended field.

    See the appropriate Linkly Third Party Processor (TPP) specification for a list of supported extended fields.

    Basket Command Full Example

    Full Basket Example

    {  
        "id": "t39kq18134553",  
        "amt": 18700,  
        "tax": 1760,  
        "dis": 650,  
        "sur": 374,  
        "items": [{  
            "id": "t39kq002",  
            "sku": "k24086723",  
            "qty": 2,  
            "amt": 2145,  
            "tax": 200,  
            "dis": 50,  
            "name": "XData USB Drive"  
        }, {  
            "id": "t39kq003",  
            "sku": "s23475697",  
            "qty": 1,  
            "amt": 8910,  
            "tax": 810,  
            "name": "MSoft OSuite",  
            "srl": "ms7843k346j23"  
        }, {  
            "id": "t39kq004",  
            "sku": "m47060855",  
            "qty": 5,  
            "amt": 1100,  
            "tax": 110,  
            "dis": 110,  
            "name": "A4 Notepad"  
        }]  
    } 
    

    The example opposite basket contains 3 items:
    2 XData USB Drives, at $21.45 each, which includes tax of $2.00 and a discount of $0.50
    1 MSoft OSuite, with a serial number, at $89.10, which includes tax of $8.10 and no discount
    5 A4 Notepads, at $11.00 each, which includes tax of $1.10 and a discount of $1.10
    The total value of the basket is $187.00, with a total tax of $17.60 and total discount of $6.50. Paying by credit card also incurred a surcharge of $3.74 (2%).

    Surcharging

    The Linkly surcharging solution is driven by the Linkly components and the payment terminal, this removes any need for the POS application to perform any complex card inspection or store and managed surcharging rates. Merchants can us the Linkly Merchant Portal to set their desired surcharging rates.

    If a surcharge is applied:

    Food & Beverage

    Linkly has created a number of payment features that help merchants make the most of their payment solution, these help POS providers quickly add important features to their food and beverage solution.

    Pay at Table

    The Linkly Pay at Table solution groups a number of payment features together to deliver the capability to process payment transactions at a table, the capabilities include:

    As the Pay at Table flow creates an alternate transaction flow (commenced from the terminal), there are dedicated Linkly features to enable.

    Overview

    The Pay at Table API provides a common interface for the terminal to utilise the EFT-Client to retrieve available tables and orders so payment functions (e.g. tender, customer receipt etc.) can be performed by an operator on the terminal without using the POS.

    The Pay at Table client requires the POS to act a data source so that it can retrieve information about available tables, orders, payment options etc.

    POS Data Source - REST Server

    When in REST server mode the Pay at Table extension will connect directly to a REST server hosted by the POS which implements the Linkly Pay at Table REST API.

    Patrestserver

    Example Transaction Flow

    1. The user initiates a Pay at Table transaction from the terminal
    2. The Linkly Pay at Table client requests the settings from the server
    3. The Linkly Pay at Table client requests a list of tables from the server
    4. Tables are presented to the user, either as a list using the DisplayName property of a Table or by allowing the user to manually key a DisplayNumber.
    5. Once the user selects a table, the Pay at Table client requests orders available on that table.
    6. If no orders are available, the Pay at Table client presents a display to the user and allows them to select another table.
    7. If orders are available the Pay at Table client presents available options for that order (e.g. print receipt, tender). If multiple orders are available, the Pay at Table client displays all available orders and asks the user to select which order to process.
    8. If the user selects the "Print Receipt" option, the Pay at Table client will request the customer receipt from the server, print it and display the order options again. If multiple print options are available from the settings, the user is asked to select which mode to print before the request is sent to the server.
    9. If the user selects the "Tender" option, the Pay at Table client starts a payment on the terminal. If multiple tender options are available from the settings, the Pay at Table client displays these options and asks the user to select the tender type before proceeding with the payment.
    10. The transaction request, display events and transaction event are sent to the server as EFTPOS commands
    11. Once the payment is complete, the Pay at Table client updates the tender with a completed state. It is assumed at this point the POS server would also update the order state.
    12. The Pay at Table client request the selected order again. If the order is complete a message is displayed on the terminal, otherwise the user is presented with the order options again.

    Pat std sd

    POS Data Source - Linkly Interface

    Linkly recommend the POS implements REST server mode. If the REST server mode doesn't suit your integration needs, please contact Linkly to discuss alternatives.

    The POS must manage the order/tender states in case of disconnection from the Pay at Table client or the terminal. If the POS loses connection from the service at any time while a tender/order is being processed, it's recommended to inquire of the last transaction's status using the GetLastTransaction call to the EFT-Client.

    Start Developing

    Install required software

    Set up Pay at Table

    REST Demo Application

    To configure the REST Demo Application

    1. Download the REST demo source from GitHub
    2. Run Visual Studio 2019 as Administrator
    3. Open and build the project "PayAtTable.ServerCore" in Visual Studio
    4. Open the Project Properties, and under Debug, take note of the App URL
    5. When you run the Linkly Pay at Table installer, enable the REST API option and enter the App URL as the server address
    6. Run the project using IIS Express. The browser should open showing the Settings launch page. When you click on Swagger, it will show the available APIs.

    Start a Pay at Table Sale

    1. Configure REST demo application
    2. On the Virtual PINpad, press FUNC + 8787 + OK
    3. Follow PINpad prompts

    Pay at Table REST API

    Linkly has created a lightweight solution for driving Pay at Table transactions which the POS needs to implement so the transactions can be commenced from the terminal.

    HTTP Response codes

    HTTP Response code Description
    200 OK The request was successful
    201 Created The request was successful, and a resource has been created
    204 No Content The request was successful, there is no content in the response
    400 Bad Request The client request is invalid
    401 Unauthorised The client needs to authenticate before it can continue
    403 Forbidden The client doesn't have access to the resource
    404 Not found The requested resource wasn't found
    500 Server Error The server encountered an internal error processing the request

    Methods

    Name HTTP Method Description
    Get Settings GET /api/settings Get settings for the Pay at Table client
    Get Tables GET /api/tables Get a lookup list of tables used to find an order
    Get Orders By Table GET /api/tables/{table-id}/orders Get a list of orders associated with a table
    Get Order GET /api/orders/{order-id} Get an order based on an order id.
    Get Customer Receipt From Order GET /api/orders/{order-id}/receipt?receiptOptionId=[string] Get a customer receipt for a given order. Can accept an optional receipt option id.
    Update Order PUT /api/orders/{order-id} Update an order
    Create Tender POST /api/tenders Create a tender
    Update Tender PUT /api/tenders/{tender-id} Update a tender
    Create EFTPOS Command POST /api/eftpos/commands Create an EFTPOS command

    Get Settings

    GET /api/settings 
    
    HTTP/1.1 200 OK 
    Content-type: application/json 
    { 
        "Settings": { 
            "TenderOptions": [{ 
                "Id": "0", 
                "TenderType": 0, 
                "Merchant": "0", 
                "DisplayName": "EFTPOS", 
                "EnableSplitTender": false, 
                "EnableTipping": true, 
                "CsdReservedString2": "EFTPOS", 
                "TxnType": "P", 
                "PurchaseAnalysisData": "" 
            }], 
    
            "ReceiptOptions": [{ 
                "Id": "0", 
                "ReceiptType": 0, 
                "DisplayName": "Customer" 
            }], 
    
            "PrinterOption": { 
                "PrintMode": 0, 
                "Location": -1, 
                "StaticReceipt": ["line1", "line2", "line3", "line4"] 
            } 
        } 
    } 
    

    Description

    Get the settings for the pay at table client

    Request

    Do not supply a request body for this method.

    Response

    If successful, the body contains a PATResponse object with the Settings property populated a Settings object.

    Supported response codes: 200, 400, 401, 403 and 500.

    Properties

    Name Type Description
    TenderOptions TenderOption[] Lists the tender options available to the Pay at Table client. If left null or empty the option to tender will not be available on Pay at Table client when the user selects an order. If only one option is available, the Pay at Table client will automatically select that option when the user chooses to tender.
    ReceiptOptions ReceiptOption[] Lists the tender options available to the Pay at Table client. If left null or empty the option to print will not be available on Pay at Table client when the user selects an order. If only one option is available, the Pay at Table client will automatically select that option when the user chooses an order.
    PrinterOption PrinterOption Allows for custom receipt information, appended to the header/footer of the eftpos receipt, if left null no custom receipt will be printed. You can allow Linkly to print a custom header/footer with some information about the current Transaction

    TenderOption Properties

    Name Type Description
    Id String Unique identifier.
    TenderType int The type of this tender option
    Merchant int The merchant code to use (see Appendix A - Merchant Codes). Default is 0.
    DisplayName String The text displayed in the terminal.
    EnableSplitTender Boolean If true, the split-billing workflow is enabled.
    EnableTipping Boolean If true, the tipping workflow is enabled.
    CsdReservedString2 String A Reserved String for additional functionality (see CsdReservedString2). Default is EFTPOS.
    TxnType String The type of transaction this tender applies to. Only Purchase and Refund types are allowed.
    PurchaseAnalysisData String any additional PAD value

    ReceiptOption Properties

    Name Type Description
    Id String Unique identifier.
    ReceiptType int The type of receipt for this tender option. Only 0 is supported for now.
    DisplayName String The text displayed in the terminal.

    PrinterOption Properties

    Name Type Description
    PrintMode int Determines who will handle the header/footer receipt printing, default PCEFTPOS: PCEFTPOS = 0, POS = 1, STATIC = 2.
    Location int Determines where the custom receipt will print as a header prior to eftpos receipt or after as a footer, default is None: Header = 0, Footer = 1, None = -1.
    StaticReceipt String[] The receipt to display if you set PrintMode to STATIC.

    Get Tables

    GET /api/tables 
    
    HTTP/1.1 200 OK 
    Content-type: application/json 
    { 
        "Tables": [{ 
                "Id": "50", 
                "DisplayName": "TABLE 1", 
                "DisplayNumber": 1, 
                "ServerName": "Steve" 
            }, 
            { 
                "Id": "51", 
                "DisplayName": "TABLE 2", 
                "DisplayNumber": 2, 
                "ServerName": "Steve" 
            }, 
            { 
                "Id": "52", 
                "DisplayName": "TABLE 3", 
                "DisplayNumber": 3, 
                "ServerName": "Jake" 
            } 
        ] 
    } 
    

    Description

    Get a lookup list of tables used to find an order. The Pay at Table client will either present a list of selectable items to the user using the "DisplayName" property, or request the user enter a number which will be used to find a table based on the "DisplayNumber" property. The Id property is a unique identifier for the table used in subsequent requests and is not presented to the user.

    Request

    Do not supply a request body for this method.

    Response

    If successful, the body contains a PATResponse object with the Tables property populated by an array of Table.

    Supported response codes: 200, 400, 401, 403 and 500.

    Properties

    Name Type Description
    Id String Unique identifier.
    DisplayName String Max 14 characters. A name which represents this table that could be displayed to a user.
    DisplayNumber Integer A number which represents this table that could be displayed to a user.
    ServerName String Max 8 characters. A string that represents either the servers name or employee ID.

    Get Orders by Table

    GET /api/tables/{table-id}/orders 
    
    HTTP/1.1 200 OK 
    Content-type: application/json 
    { 
        "Orders": [{ 
            "Id": "101", 
            "DisplayName": "Elsa", 
            "OrderState": 0, 
            "AmountOwing": 100.00, 
            "TableId": "50" 
        }] 
    } 
    

    Description

    Get a list of orders associated with a table.

    The Pay at Table client will send this request after a user has selected one of the tables returned from a previous call to Get Tables.

    Request

    GET /api/tables/{table-id}/orders

    Do not supply a request body for this method

    Parameter Type Description
    table-id String Required. The id of an table orders are being requested from.

    Response

    If successful, the body contains a PATResponse object with the Orders property populated by an array of Order.

    Supported response codes: 200, 400, 401, 403 and 500.

    Properties

    Name Type Description
    Id String Unique identifier. Read only.
    DisplayName String Max 14 characters. A name which represents this table that could be displayed to a user.
    OrderState Integer The state of the order. This is used by the Pay at Table client to determine if an order is available for tender. Possible values: (0) Pending – The order exists, but isn't yet available for tender. (10) Active – The order exists and is available for tender. (20) Tendering – A tender is currently in progress. The result is not known. The order is not available for tender. (30) Complete – The order is complete and is not available for tender.
    AmountOwing Decimal The outstanding amount on this order. This is used by the Pay at Table client to determine the maximum tender amount.
    TableId String The id of the Table attached to this order.

    Get Order

    GET /api/orders/{order-id} 
    
    HTTP/1.1 200 OK 
    Content-type: application/json 
    { 
        "Order": { 
            "Id": "101", 
            "DisplayName": "Elsa", 
            "OrderState": 0, 
            "AmountOwing": 100.00, 
            "TableId": "50" 
        } 
    } 
    

    Description

    Get an order based on an order id. 

    The Pay at Table client will send this request after a user has selected one of the orders returned from a previous call to Get Orders by Table.

    Request

    Do not supply a request body for this method.

    Parameter Type Description
    order-id String Required. The id of the order being requested.

    Response

    If successful, the body contains a PATResponse object with the Order property populated by an Order.

    Supported response codes: 200, 400, 401, 403, 404 and 500.

    Properties

    Name Type Description
    Id String Unique identifier. Read only.
    DisplayName String Max 14 characters. A name which represents this table that could be displayed to a user.
    OrderState Integer The state of the order. This is used by the Pay at Table client to determine if an order is available for tender. Possible values: (0) Pending – The order exists, but isn't yet available for tender. (10) Active – The order exists and is available for tender. (20) Tendering – A tender is currently in progress. The result is not known. The order is not available for tender. (30) Complete – The order is complete and is not available for tender.
    AmountOwing Decimal The outstanding amount on this order. This is used by the Pay at Table client to determine the maximum tender amount.
    TableId String The id of the Table attached to this order.

    Get Customer Receipt from Order

    GET /api/orders/{order-id}/receipt?receiptOptionId=[string]
    
    HTTP/1.1 200 OK 
    { 
        "Receipt": { 
            "Lines": ["Line 1","Line 2","Line 3"] 
        } 
    } 
    

    Description

    Get a customer receipt based on an order id. 

    Request

    Do not supply a request body for this method

    Parameter Type Description
    order-id String Required. The id of the order the receipt is being requested from.
    receiptOptionId String Optional. The id of the ReceiptOption used to generate this receipt request. Note: id '99' is reserved for custom header/footer receipt from POS

    Response

    If successful, the body contains a PATResponse object with the Receipt property populated by a Receipt.

    Supported response codes: 200, 400, 401, 403, 404 and 500.

    Update Order

    PUT /api/orders/{order-id} 
    Content-type: application/json 
    { 
        "Order": { 
            "Id": "200",
            "DisplayName": "Order 99",
            "OrderState": 30,
            "AmountOwing": 0.00,
            "TableId": "50"
        } 
    } 
    
    HTTP/1.1 200 OK 
    Content-type: application/json 
    { 
        "Order": { 
            "Id": "200",
            "DisplayName": "Order 99",
            "OrderState": 30,
            "AmountOwing": 0.00,
            "TableId": "50"
        } 
    } 
    

    Description

    Updates an order. This is called before the Create Tender to mark the order as Tendering. If the update is successful, the Create Tender is called next. It is called again after a payment has been processed to mark the status of the order. The AmountOwing and OrderState will be updated according to the result of the payment. For example, if the payment was fully paid, the order will be updated as Completed and the AmountOwing is set as zero. If the payment is partial, it will be set again to Active and the AmountOwing will reflect the remaining balance. If the payment was canceled, the status will be set to Active and the AmountOwing will remain the same.

    The Id property must point to a valid order and match the {order-id} in the request URL.

    Request

    The request body contains a PATRequest with the Tender property populated by a Tender.

    Parameter Type Description
    order-id String Required. The id of the order being updated.

    Response

    If successful, this method returns a PATResponse object with the Order property populated by a Order. In most cases the Order in the response will mirror the request.

    Properties

    Name Type Description
    Id String Unique identifier. Read only.
    DisplayName String Max 14 characters. A name which represents this order that could be displayed to a user.
    OrderState Integer The state of the order. This is used by the Pay at Table client to determine if an order is available for tender. Possible values: (0) Pending – The order exists, but isn't yet available for tender. (10) Active – The order exists and is available for tender. (20) Tendering – A tender is currently in progress. The result is not known. The order is not available for tender. (30) Complete – The order is complete and is not available for tender.
    AmountOwing Decimal The outstanding amount on this order. This is used by the Pay at Table client to determine the maximum tender amount.
    TableId String The id of the Table attached to this order.

    Create Tender

    POST /api/tenders 
    { 
        "Tender": { 
            "Id" : null, 
            "OrderId": "101", 
            "TenderOptionId": "0", 
            "TenderState": 0, 
            "AmountPurchase": 100.00, 
            "OriginalAmountPurchase ": 100.00 
        } 
    } 
    
    HTTP/1.1 201 OK 
    Content-type: application/json 
    { 
        "Tender": { 
            "Id": "1042", 
            "OrderId": "101", 
            "TenderOptionId": "0", 
            "TenderState": 0, 
            "AmountPurchase": 100.00, 
            "OriginalAmountPurchase": 100.00 
        } 
    } 
    

    Description

    Creates a tender. A tender is an object which contains information about a payment.

    Request

    The request body contains a PATRequest with the Tender property populated by a Tender.

    The OrderId property must reference a valid order.

    The TenderOptionId property references the tender option selected by the user.

    Response

    If successful, the body will contain a PATResponse object with the Tender property populated by a Tender. The Tender in the response will have the Id property populated by a unique Id.

    Supported response codes: 201, 400, 401, 403, 404 and 500.

    Properties

    Name Type Description
    Id String Unique identifier. Read only.
    TenderOptionId String The id of the tender option the operator selected to create this tender
    TenderState Integer The state of a tender is defined by the TenderState property. The initial state is set to Pending (0). When the payment is complete the Tender object will be updated and the TenderState changed to CompletedSuccessful (1) or CompletedUnsuccessful (2).
    AmountPurchase Decimal The amount of this tender (see notes)
    Original AmountPurchase Decimal If the tender amount is changed (e.g. A $100 purchase on a gift card is completed for the remaining amount on the card - $80.50) this value will reflect the original tender amount before it was changed.
    OrderId String The id of the order this tender is attached to.

    Update Tender

    PUT /api/tenders/{tender-id} 
    Content-type: application/json 
    { 
        "Tender": { 
            "Id": "1042", 
            "TenderOptionId": "0", 
            "OrderId": "101", 
            "TenderState": 2, 
            "AmountPurchase": 80.50, 
            "OriginalAmountPurchase": 100.00 
        } 
    } 
    
    HTTP/1.1 200 OK 
    Content-type: application/json 
    { 
        "Tender": { 
            "Id": "1042", 
            "TenderOptionId": "0", 
            "OrderId": "101", 
            "TenderState": 2, 
            "AmountPurchase": 80.50, 
            "OriginalAmountPurchase": 100.00 
        } 
    } 
    

    Description

    Updates a tender. It is possible that the AmountPurchase in an updated tender will not be the same as the AmountPurchase in the original tender. E.g. A $100 purchase on a giftcard is completed for the remaining amount on the card ($80.50).

    The Id property must point to a valid tender and match the {tender-id} in the request URL. The OrderID property must point to a valid order.

    Request

    The request body contains a PATRequest with the Tender property populated by a Tender.

    Parameter Type Description
    tender-id String Required. The id of the tender being updated.

    Response

    If successful, this method returns a PATResponse object with the Tender property populated by a Tender. In most cases the Tender in the response will mirror the request.

    Properties

    Name Type Description
    Id String Unique identifier. Read only.
    TenderOptionId String The id of the tender option the operator selected to create this tender
    TenderState Integer The state of a tender is defined by the TenderState property. The initial state is set to Pending (0). When the payment is complete the Tender object will be updated and the TenderState changed to CompletedSuccessful (1) or CompletedUnsuccessful (2).
    AmountPurchase Decimal The amount of this tender (see notes)
    Original AmountPurchase Decimal If the tender amount is changed (e.g. A $100 purchase on a gift card is completed for the remaining amount on the card - $80.50) this value will reflect the original tender amount before it was changed.
    OrderId String The id of the order this tender is attached to.

    Create EFTPOS Command

    POST /api/eftpos/commands 
    { 
        "EFTPOSCommand": { 
            "TenderId": "0",  
            "OriginalEFTPOSCommandId": "0",  
            "EFTPOSCommandType": 0,  
            "EFTPOSCommandState": 20 
            "AccountType": "", 
            "AmtCash": 0.0, 
            "AmtPurchase": 100.0, 
            "AmtTip": 0.0, 
            "AmtTotal": 0.0, 
            "Application": "", 
            "AuthCode": "", 
            "Caid": "", 
            "Catid": "", 
            "CardName": "", 
            "CardType": "", 
            "CsdReservedString1": "", 
            "CsdReservedString2": "", 
            "CsdReservedString3": "", 
            "CsdReservedString4": "", 
            "CsdReservedString5": "", 
            "CsdReservedBool1": false, 
            "CutReceipt": false, 
            "CurrencyCode": "", 
            "DataField": "", 
            "Date": "", 
            "DateExpiry": "", 
            "DateSettlement": "", 
            "DialogPosition": "", 
            "DialogTitle": "", 
            "DialogType": "", 
            "DialogX": 0, 
            "DialogY": 0, 
            "EnableTip": false, 
            "EnableTopmost": false, 
            "Merchant": "", 
            "MessageType": "", 
            "PanSource": " ", 
            "Pan": "", 
            "PosProductId": "", 
            "PurchaseAnalysisData": "", 
            "ReceiptAutoPrint": false, 
            "ResponseCode": "", 
            "ResponseText": "", 
            "Rrn": "", 
            "Success": false, 
            "Stan": "", 
            "Time": "", 
            "TxnRef": "", 
            "TxnType": "", 
            "Track1": "", 
            "Track2": "" 
        } 
    } 
    
    POST /api/eftpos/commands 
    {
       "EFTPOSCommand":{
          "CsdReservedString1":"000000002",
          "CsdReservedString5":"0",
          "DataField":"PROCESSING          PLEASE WAIT         ",
          "EFTPOSCommandType":400,
          "TenderId":"5"
        }
    }
    
    POST /api/eftpos/commands 
    {
       "EFTPOSCommand":{
          "CsdReservedString5":"C",
          "EFTPOSCommandType":401,
          "Receipt":"------------------------\r\n *** TRAINING MODE ***  \r\n  TEST MERCHANT TITLE   \r\n   TEST MERCHANT NAME   \r\n         LINE2          \r\n                        \r\n15:18:09 04/11/20       \r\n                        \r\nCREDIT ACCOUNT          \r\n                        \r\nPURCHASE   AUD     $1.00\r\nSURCHARGE  AUD     $0.22\r\n                --------\r\nTOTAL      AUD     $1.22\r\n                        \r\nAPPROVED -  00          \r\n                        \r\nPLEASE RETAIN AS RECORD \r\n      OF PURCHASE       \r\n------------------------\r\n",
          "TenderId":"5"
       }
    }
    
    HTTP/1.1 200 OK 
    Content-type: application/json 
    { 
        "EFTPOSCommand": { 
            "TenderId": "0",  
            "OriginalEFTPOSCommandId": "0",  
            "EFTPOSCommandType": 0,  
            "EFTPOSCommandState": 20 
            "AccountType": "", 
            "AmtCash": 0.0, 
            "AmtPurchase": 100.0, 
            "AmtTip": 0.0, 
            "AmtTotal": 0.0, 
            "Application": "", 
            "AuthCode": "", 
            "Caid": "", 
            "Catid": "", 
            "CardName": "", 
            "CardType": "", 
            "CsdReservedString1": "", 
            "CsdReservedString2": "", 
            "CsdReservedString3": "", 
            "CsdReservedString4": "", 
            "CsdReservedString5": "", 
            "CsdReservedBool1": false, 
            "CutReceipt": false, 
            "CurrencyCode": "", 
            "DataField": "", 
            "Date": "", 
            "DateExpiry": "", 
            "DateSettlement": "", 
            "DialogPosition": "", 
            "DialogTitle": "", 
            "DialogType": "", 
            "DialogX": 0, 
            "DialogY": 0, 
            "EnableTip": false, 
            "EnableTopmost": false, 
            "Merchant": "", 
            "MessageType": "", 
            "PanSource": " ", 
            "Pan": "", 
            "PosProductId": "", 
            "PurchaseAnalysisData": "", 
            "ReceiptAutoPrint": false, 
            "ResponseCode": "", 
            "ResponseText": "", 
            "Rrn": "", 
            "Success": false, 
            "Stan": "", 
            "Time": "", 
            "TxnRef": "", 
            "TxnType": "", 
            "Track1": "", 
            "Track2": "" 
        } 
    } 
    

    Description

    Create an EFTPOS command. The fields defined will vary based on the EFTPOSCommandType as described in the Properties section below. EFTPOSCommandType are 200 for TransactionEvent, 400 for DisplayEvent, and 401 for PrintEvent.

    Request

    The request body contains a PATRequest with the EFTPOSCommand property populated by an EFTPOSCommand

    Response

    If successful, this method returns a PATResponse object with the EFTPOSCommand property populated by an EFTPOSCommand. In most cases the EFTPOSCommand in the response will mirror the request.

    Properties

    Note: All message handling should be case-insensitive.

    TransactionEvent

    Name Type Description
    Id String Unique identifier. Read only.
    TenderId String Id of the tender that this EFTPOS command is associated with
    OriginalEFTPOS CommandId String The id of the original EFTPOS request if this is an event.
    EFTPOSCommand Type Integer 200
    EFTPOSCommand State Integer AwaitingDeviceAck = 0, AwaitingDeviceResponse = 10, CompletedSuccessful = 20, CompletedUnsuccessful = 30
    AccountType String The account type used
    AmtCash Decimal The cash amount
    AmtPurchase Decimal The purchase amount
    AmtTip Decimal The tip amount
    AmtTotal Decimal The total amount
    Application String The card application used
    AuthCode String The transaction authorisation code
    Caid String The CAID of the terminal used
    Catid String The CATID of the terminal used
    CardName String N/A
    CardType String N/A
    CsdReservedString1 String N/A
    CsdReservedString2 String N/A
    CsdReservedString3 String N/A
    CsdReservedString4 String N/A
    CsdReservedString5 String N/A
    CsdReservedBool1 Boolean N/A
    CutReceipt Boolean N/A
    CurrencyCode String The transactions currency code
    DataField String
    Date String The date
    DateExpiry String N/A
    DateSettlement String The settlement date of the transaction
    DialogPosition String
    DialogTitle String
    DialogType String
    DialogX Integer
    DialogY Integer
    EnableTip Boolean N/A
    EnableTopmost Boolean
    Merchant String
    MessageType String
    PanSource String N/A
    Pan String N/A
    PosProductId String
    PurchaseAnalysisData String Purchase Analysis Data, contains any transaction specific tag data
    ReceiptAutoPrint Boolean
    ResponseCode String The response code from the acquiring bank
    ResponseText String The response text associated with the response code
    Rrn String Retrieval reference number
    Success Boolean Status of the transaction
    Stan String System Trace Audit Number
    Time String The time
    TxnRef String Transaction reference number
    TxnType String Transaction type, eg. Purchase
    Track1 String N/A
    Track2 String N/A

    DisplayEvent

    Name Type Description
    EFTPOSCommand Type Integer 400
    TenderId String Id of the tender that this EFTPOS command is associated with
    DataField String The text displayed in the terminal.
    CsdReservedString1 String N/A
    CsdReservedString5 String N/A

    PrintEvent

    Name Type Description
    EFTPOSCommand Type Integer 401
    TenderId String Id of the tender that this EFTPOS command is associated with
    Receipt String The id of the original EFTPOS request if this is an event.
    CsdReservedString5 String N/A

    REST Server Authorization

    The following options are available to secure the communication between the POS and the Pay-at-table component:

    Authorisation Header

    The POS server developer needs to provide the authorization header type (Basic or Bearer) and token for the Pay-at-table component to use when sending the API requests. This value must be given to Linkly Cloud Portal admin to be configured for testing and deployment.

    Server-side validation

    The Pay-at-table component can also be configured to validate the server certificates. The actual server CA certificate file must be given to Linkly Cloud Portal admin to be configured for testing and deployment.

    Client-side validation

    The Pay-at-table component can also be configured to send client certificates for each API request to the POS server. The POS server can then validate the certificate it receives based on whichever criteria agreed with Linkly. The actual certificate files must be configured by Linkly Cloud Portal admin to be configured for testing and deployment.

    Error Codes

    The following error codes will be displayed in the terminal if any of the described scenarios occur:

    Code Description
    ZA Failed to retrieve table
    ZB Failed to create tender
    ZC Failed to update tender
    ZD Failed to retrieve order
    ZE Failed to retrieve settings
    ZF Failed to update order before tendering
    ZG Failed to update order after tendering

    Tipping

    The Linkly tipping feature supports the ability for customers to collect a tip on the terminal as part of the payment transaction.

    Linkly's components will manage the configuration and the terminal is used to interact with the cardholder to streamline the process of tipping.

    To enable tipping, configure the tipping values in the Linkly Merchant Portal, and set EnableTip to '1' in the transaction request.

    If a tip is applied:

    This feature supports the following tip entry methods:

    To provide POS partners with the flexibility to use their own tipping solutions Linkly supports the following requests as part of the transaction method.

    The TIP tag can be used by the POS to send the TIP value to the terminal for inclusion on the customer copy of the eftpos receipt, this is only required if the POS wants to implement it's own tipping solution, for all other instances nothing is needed from the POS to enable tipping for a merchant.

    TIP tag definition

    API Specification

    All Requests and Responses are wrapped in ApiRequest and ApiResponse JSON objects respectively.

    ApiRequest

    Example APIRequest object

    {
        "Request":{
            "somekey":"somevalue",
            "somekey":"somevalue",
            ....
        },
        "Notification":{
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    A request to the Linkly Cloud REST API is made up of two JSON objects a "Request" and a "Notification" (optional for sync mode, mandatory for async mode).
    The "Request" object will contain all the information a POS will send to make a request, be it a transaction or a settlement.

    The "Notification" object contains information about the POS' web server that is capable of receiving responses from the Linkly Cloud REST API about its current requests. Most requests will generate display responses and receipt responses in addition to the original request response that the POS is expected to handle. All these will be in JSON wrapped in a "Response" object and contain a "sessionId".

    GET and POST Requests
    All requests are made using POST except for transaction which also has GET functionality. When using GET on transaction the POS must send the sessionId of the transaction they want retrieved, the POS will either receive a 202 "in progress" or a 200 OK with the transaction response in the body.

    ApiResponse

    Example APIResponse object

    {
        "sessionId":"a1b2c3d4e5",
        "responseType":"transaction",
        "Response"{
            "somekey":"somevalue",
            "somekey":"somevalue",
        }
    }
    

    An ApiResponse is made up of a "Response" object which contains the information relating to the original request such as a transaction.

    It also contains a "sessionId", a valid uuid which forms the unique session identifier for this request.

    Finally the Linkly Cloud REST API also sends a ResponseType field which contains an identifier for this response.

    It's important to understand what the Cloud API response means, and that there are at least two layers to responses.

    HTTP Response

    The REST API is a layer on top of back-end EFT services. The API has its own response codes to indicate error conditions in the API itself which have no relation to anything financial or transaction-related. It does this with HTTP Status Codes. There are two "non-error" HTTP status codes, HTTP 200 and HTTP 202.

    HTTP 200 OK

    This indicates that the request was able to be processed successfully, but does not say what the result of that request is.

    Example 1:

    You POST a synchronous Transaction to the API for a purchase of $10. The API responds with HTTP 200 and an ApiResponse. The HTTP 200 response code indicates that it was able to pass on the transaction to the EFT Client, and got a transaction response. It does not mean the transaction was successful. In order to check if the transaction was successful (ie. money was actually transferred) you need to check the Response's Success flag.

    Example 2:

    You POST a Logon request to the API, but the PIN pad is offline. The API responds with HTTP 200, indicating that it was able to relay the request to the EFT Client, and the EFT Client gave a valid response back. Again, you need to inspect the Response to determine that the PIN pad is offline.

    Example 3:

    After a power failure, your POS enters error recovery to determine the status of the last transaction it sent. Upon sending the GET Transaction Status request, the API responds with an HTTP 404 Unauthorised response. This is no reflection on the original transaction, but instead the POS refreshes its token and retries the request. This time it receives an HTTP 200, which once again needs to be inspected to find out if the transaction was actually successful.

    HTTP 202 Accepted

    This indicates that the request has been accepted by the API and it is currently processing that request. It does not indicate that the transaction request has necessarily been "accepted" yet by either the EFT Client, PIN pad, or bank. You should wait for the transaction response and determine the result from that.

    Other HTTP status codes

    All other status codes besides 200 and 202 indicate that the API was unable to fulfill the REST request, not whether or not the transaction succeeded (although you can sometimes determine unsuccessful requests based on HTTP status code).

    ** Example 1:**

    You POST a synchronous Transaction to the API for a purchase of $10. The API responds with HTTP 500. This indicates that there's something wrong with either the API itself or infrastructure around the API. Examples may include: internet outages, server overloading, etc. The POS should enter error recovery to find out whether it was successful.

    ** Example 2:**

    You POST a synchronous Transaction to the API for a purchase of $10. The API responds with HTTP 401. This indicates that the authorisation token is not valid and needs to be renewed. In this case it can be safely assumed that the transaction was not successful yet, but the POS should renew the token and try again.

    EFT Response

    The next layer is the EFT Reponse, which is found inside the API Response. The EFT Response is received in one of only 3 ways:

    1. As a notification message posted to the POS's appropriate endpoint, if supplied
    2. In the body of the response to an HTTP POST request (eg. Transaction, Status or Logon), but only where the HTTP Status code is 200.
    3. In the body of the response to an HTTP GET transaction status request.

    Methods

    Transaction

    Transaction request

    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/$(uuidgen)/transaction?async=false" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json' \
      -d '{
            "request": {
              "txnType": "P",
              "amtPurchase": 100,
              "txnRef": "0123456789ABCDEF"
            }
          }'
    
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var requestContent = new
    {
        Request = new
        {
            TxnType = "P",
            AmtPurchase = 100,
            TxnRef = DateTime.Now.ToString("yyMMddhhmmssffff"),
        }
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{Guid.NewGuid().ToString()}/transaction?async=false")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import uuid
    import requests; # http://python-requests.org
    
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    request_payload = {
        'request': {
            'txnType': 'P',
            'amtPurchase': 100,
            'txnRef': datetime.datetime.now().strftime('%y%m%d%H%M%S%f')[:-4]
        }
    }
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + str(uuid.uuid4()) + '/transaction?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.post(uri, json=request_payload, headers=headers)
    response_payload = response.json()
    

    Send a transaction request (e.g. purchase, refund, cash out).

    URI Path

    POST ~/v1/sessions/<<sessionid>>/transaction

    URI Query Parameters

    Parameter Value
    async 'true' for asynchronous mode, 'false' for synchronous mode

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Transaction Request Object

    Example transaction request object

    {
        "Request": 
        {
            "AmtPurchase": 100,
            "TxnType": "P",
            "TxnRef": "1234567890",
            "Basket": 
            {  
                "id": "t39kq18134553",  
                "amt": 2145,  
                "tax": 200,  
                "dis": 50,  
                "sur": 0,  
                "items": [{  
                    "id": "t39kq002",  
                    "sku": "k24086723",  
                    "qty": 2,  
                    "amt": 2145,  
                    "tax": 200,  
                    "dis": 50,  
                    "name": "XData USB Drive"  
                }]  
            } 
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field KeyName Type Required Description
    Merchant string(2) Merchant to send the Transaction to (default 0, EFTPOS 0) use merchant '0' unless performing TPP transactions
    ReceiptAutoPrint string(1) Variable Indicates if the POS is to receive receipt events. See ReceiptAutoPrint for available values
    CutReceipt string(1) Indicates whether Linkly should cut receipts. Defaults to '0' (DontCut)
    TxnType string(1) Yes Required. Indicated the type of transaction to perform
    CurrencyCode string(3) Currency code for this transaction (e.g. AUD) A 3-digit ISO currency code. Defaults to " "(NotSet)
    OriginalTxnType string(1) The original type of transaction for voucher entry. Defaults to 'P' (PurchaseCash)
    Date string(12) Yes Nullable. Original transaction time. Used for voucher or completion only
    Time string(12) Nullable. Original transaction time. Used for voucher or completion only
    TrainingMode bool Nullable. Determines if the transaction is a training mode transaction.
    Set to TRUE if the transaction is to be performed in training mode. The default is FALSE.
    EnableTip bool Nullable. Set to TRUE if tipping is to be enabled for this transaction. The default is FALSE
    AmtCash number In Cents. The cash amount for the transaction. This property is mandatory for a 'C' transaction type.
    AmtPurchase number Yes In Cents. The purchase amount for the transaction.
    AuthCode string(6) Nullable. The authorisation number for the transaction. Defaults to 0
    TxnRef string(16) Yes Required.
    PanSource string(1) Indicates the source of the PAN. Use this property for card not present transactions. Defaults to ' ' (PIN pad)
    Pan string(20) The PAN to use when pan source of POS keyed is used. Use this property in conjunction with PanSource
    DateExpiry string(4) The expiry date of the card when of POS keyed is used. In MMYY format. Use this property in conjunction with PanSource when passing the card expiry date to Linkly.
    Track2 string(40) The track 2 to use when of POS swiped is used. Use this property in conjunction with PanSource
    AccountType string(1) The account to use for this transaction. Defaults to ' ' (prompt user)
    RRN string(12) The retrieval reference number for the transaction. Only required for some transaction types
    PurchaseAnalysisData object Extended fields. See Purchase Analysis Data section for details
    Basket object See basket section for details

    Transaction Response HTTP Status Codes

    Code Description Required action
    200 Only for synchronous mode. The transaction completed and a valid response has been returned. The 'success' property in the response object indicates the financial success of the transaction. Check the body for an APIResponse object
    202 Only for asynchronous mode. The transaction has been started. Response body will be null. The POS should await the result in its Notification postback
    400 Invalid request. The transaction has not completed successfully. Report the error and notify the operator. Do not retry.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again. If this persists, the password may have changed.
    404 Resource not found. The transaction was not submitted successfully. The request URI is not configured properly. Report the error and notify the operator. Do not retry.
    408 A transient error has occurred. The POS should enter error recovery
    500-599 A server error has occurred. The POS should enter error recovery

    Transaction Response Object

    Example transaction response object

    {
        "SessionId": "dd250a0c81c202b66220d7379b338b8f",
        "ResponseType": "transaction",
        "Response": {
            "TxnType": "P",
            "Merchant": "00",
            "CardType": "AMEX CARD           ",
            "CardName": "05",
            "RRN": "123456789012",
            "DateSettlement": "2018-07-31T00:00:00",
            "AmtCash": 0,
            "AmtPurchase": 100,
            "AmtTip": 0,
            "AuthCode": 123456,
            "TxnRef": "1234567890      ",
            "Pan": "37601234567890      ",
            "DateExpiry": "4909",
            "Track2": "37601234567890=0949?,,S, YES, 05??????  ",
            "AccountType": "2",
            "TxnFlags": {
                "Offline": "1",
                "ReceiptPrinted": "0",
                "CardEntry": "S",
                "CommsMethod": "0",
                "Currency": "0",
                "PayPass": "0",
                "UndefinedFlag6": "0",
                "UndefinedFlag7": "0"
            },
            "BalanceReceived": false,
            "AvailableBalance": 0,
            "ClearedFundsBalance": 0,
            "Success": true,
            "ResponseCode": "00",
            "ResponseText": "APPROVED            ",
            "Date": "2018-07-31T16:14:40",
            "Catid": "12345678",
            "Caid": "0987654321     ",
            "Stan": 0,
            "PurchaseAnalysisData": {}
        }
    }
    
    Field KeyName Type (Length) Description
    Merchant string(2) Merchant to send the Transaction to (default 0, EFTPOS 0) use merchant '0' unless performing TPP transactions
    CardType string(20) Indicates the card type that was used in the transaction.
    CardName string(2) BIN Number of the card
    TxnType string(1) Required. Indicated the type of transaction to perform
    DateSettlement string(12) Indicates which settlement batch this transaction will be included in.
    AmtTip number In cents. The tip amount for the transaction.
    TxnFlags object Flags that indicate how the transaction was processed.
    BalanceReceived bool Indicates if an available balance is present in the response.
    AvailableBalance number Balance available on the processed account.
    ClearedFundsBalance number Cleared balance on the processed account.
    AmtCash number In cents. The cash amount for the transaction. This property is mandatory for a 'C' transaction type.
    AmtPurchase number In cents. The purchase amount for the transaction.
    Success bool Indicates if the request was successful.
    TxnRef string(16) The reference number to attach to the transaction. This will appear on the receipt.
    ResponseCode string(2) The response code of the request.
    Pan string(20) The PAN to use when pan source of POS keyed is used. Use this property in conjunction with PanSource
    ResponseText string(20) The response text for the response code.
    Track2 string(40) The track 2 to use when of POS swiped is used. Use this property in conjunction with PanSource
    Date string(12) Date and time of the response returned by the bank
    RRN string(12) The retrieval reference number for the transaction. Only required for some transaction types
    Catid string(8) Terminal ID configured in the PIN pad.
    Caid string(15) Merchant ID configured in the PIN pad.
    Stan number System Trace Audit Number
    PurchaseAnalysisData object Extended fields. See Purchase Analysis Data section for details

    Synchronous mode of communication

    The sequence diagram for a sample successful transaction in synchronous mode of communication is shown below

    Synchronous successful purchase

    Asynchronous mode of communication

    The sequence diagram for a sample successful transaction in asynchronous mode of communication is shown below

    Asynchronous successful purchase

    Transaction Status

    Transaction status request

    # replace <<sessionId>> with the sessionId of the transaction to retrieve
    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/<<sessionId>>/transaction?async=false" \
      -X GET \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json'
    
    var sessionId = "<<sessionId>>"; // replace <<sessionId>> with the sessionId of the transaction to retrieve
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var request = new HttpRequestMessage(HttpMethod.Get, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{sessionId}/transaction?async=false");
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import uuid
    import requests; # http://python-requests.org
    
    sessionId = '<<sessionId>>' # replace <<sessionId>> with the sessionId of the transaction to retrieve
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + sessionId + '/transaction?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.get(uri, headers=headers)
    response_payload = response.json()
    

    Request the status of a previous transaction.

    URI Path

    GET ~/v1/sessions/<<sessionid>>/transaction

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Transaction Status Response HTTP Status Codes

    Code Description Required action
    200 The transaction completed and a valid response has been returned. The 'success' property in the response object indicates the financial success of the requested transaction. Check the body for an APIResponse object
    202 The transaction has been started. Response body will be null. The POS should wait a few seconds and try again.
    400 Invalid request. It is likely that the session Id is not a valid UUID. Report the error and notify the operator. Do not retry.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again. If this persists, the password may have changed.
    404 Resource not found. Either the request URI is wrong or the transaction was not submitted successfully and could not be found. Check to ensure that the URI is correct. If in Recovery mode, the original transaction can be retried.
    408 A transient error has occurred. Wait a few seconds and retry
    500-599 A server error has occurred. Wait a few seconds and retry

    Transaction Status Response Body

    Exmaple transaction status response

    {
        "SessionId": "dd250a0c81c202b66220d7379b338b8f",
        "ResponseType": "transaction",
        "Response": {
            "TxnType": "P",
            "Merchant": "00",
            "CardType": "AMEX CARD           ",
            "CardName": "05",
            "RRN": "123456789012",
            "DateSettlement": "2018-07-31T00:00:00",
            "AmtCash": 0,
            "AmtPurchase": 100,
            "AmtTip": 0,
            "AuthCode": 123456,
            "TxnRef": "1234567890      ",
            "Pan": "37601234567890      ",
            "DateExpiry": "4909",
            "Track2": "37601234567890=0949?,,S, YES, 05??????  ",
            "AccountType": "2",
            "TxnFlags": {
                "Offline": "1",
                "ReceiptPrinted": "0",
                "CardEntry": "S",
                "CommsMethod": "0",
                "Currency": "0",
                "PayPass": "0",
                "UndefinedFlag6": "0",
                "UndefinedFlag7": "0"
            },
            "BalanceReceived": false,
            "AvailableBalance": 0,
            "ClearedFundsBalance": 0,
            "Success": true,
            "ResponseCode": "00",
            "ResponseText": "APPROVED            ",
            "Date": "2018-07-31T16:14:40",
            "Catid": "12345678",
            "Caid": "0987654321     ",
            "Stan": 0,
            "PurchaseAnalysisData": {}
        }
    }
    
    Field KeyName Description
    Merchant Merchant to send the Transaction to (default 0, EFTPOS 0) use merchant '0' unless performing TPP transactions
    CardType Indicates the card type that was used in the transaction.
    CardName BIN Number of the card
    TxnType Required. Indicated the type of transaction to perform
    DateSettlement Indicates which settlement batch this transaction will be included in.
    AmtTip The tip amount for the transaction.
    TxnFlags Flags that indicate how the transaction was processed.
    BalanceReceived Indicates if an available balance is present in the response.
    AvailableBalance Balance available on the processed account.
    ClearedFundsBalance Cleared balance on the processed account.
    AmtCash In Cents. The cash amount for the transaction. This property is mandatory for a 'C' transaction type.
    AmtPurchase In Cents. The purchase amount for the transaction.
    Success Indicates if the request was successful.
    TxnRef Required.
    ResponseCode The response code of the request.
    Pan The PAN to use when pan source of POS keyed is used. Use this property in conjunction with PanSource
    ResponseText The response text for the response code.
    Track2 The track 2 to use when of POS swiped is used. Use this property in conjunction with PanSource
    Date Date and time of the response returned by the bank
    RRN The retrieval reference number for the transaction. Only required for some transaction types
    Caid Terminal ID configured in the PIN pad.
    Stan Merchant ID configured in the PIN pad.
    PurchaseAnalysisData Extended fields. See Purchase Analysis Data section for details

    Status

    Status request

    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/$(uuidgen)/status?async=false" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json' \
      -d '{
            "request": {
              "statusType": "0"
            }
          }'
    
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var requestContent = new
    {
        Request = new
        {
            StatusType = "0"
        }
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{Guid.NewGuid().ToString()}/status?async=false")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import uuid
    import requests; # http://python-requests.org
    
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    request_payload = {
        'request': {
            'statusType': '0'
        }
    }
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + str(uuid.uuid4()) + '/status?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.post(uri, json=request_payload, headers=headers)
    response_payload = response.json()
    

    Instruct the EFT-Client to send a status message to the PIN pad to check if the PIN pad is available for use.

    URI Path

    POST ~/v1/sessions/<<sessionid>>/status

    URI Query Parameters

    Parameter Value
    async 'true' for asynchronous mode, 'false' for synchronous mode

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Status Request Object

    Example status request object

    
    {
        "Request": {
            "Merchant": "00",
            "StatusType": "0"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field KeyName Required Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Application Indicates where the request is to be sent to. Defaults to "00" (EFTPOS)
    StatusType Type of status to perform. Defaults to '0' (standard)

    Status Response HTTP Status Codes

    Code Description
    200 Only for synchronous mode. The request completed and a valid response has been returned from the PIN pad. The 'success' property in the response object indicates the actual success of the transaction.
    202 Only for asynchronous mode. The request has been started. The POS should await the result in its notification postback (Asynchronous mode only). Response body will be null.
    400 Invalid request. The request has not completed successfully.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again
    404 Resource not found. The request was not submitted successfully.
    408 A transient error has occurred. The POS should allow the operator to try the request again.
    500-599 A server error has occurred. The POS should allow the operator to try the request again.

    Status Response Object

    Example status response object

    
    {
        "SessionId": "df8db91bbb10d62057877b5df00a89b0",
        "ResponseType": "status",
        "Response": {
            "Merchant": "00",
            "AIIC": null,
            "NII": 0,
            "Catid": "123456",
            "Caid": "654321",
            "Timeout": 0,
            "LoggedOn": false,
            "PinPadSerialNumber": "",
            "PinPadVersion": "",
            "BankCode": " ",
            "BankDescription": "",
            "KVC": "",
            "SAFCount": 0,
            "NetworkType": "3",
            "HardwareSerial": "",
            "RetailerName": "",
            "OptionsFlags": {
                "Tipping": false,
                "PreAuth": false,
                "Completions": false,
                "CashOut": false,
                "Refund": false,
                "Balance": false,
                "Deposit": false,
                "Voucher": false,
                "MOTO": false,
                "AutoCompletion": false,
                "EFB": false,
                "EMV": false,
                "Training": false,
                "Withdrawal": false,
                "Transfer": false,
                "StartCash": false
            },
            "SAFCreditLimit": 0,
            "SAFDebitLimit": 0,
            "MaxSAF": 0,
            "KeyHandlingScheme": "2",
            "CashoutLimit": 0,
            "RefundLimit": 0,
            "CPATVersion": "",
            "NameTableVersion": "",
            "TerminalCommsType": "2",
            "CardMisreadCount": 0,
            "TotalMemoryInTerminal": 0,
            "FreeMemoryInTerminal": 0,
            "EFTTerminalType": "Unknown",
            "NumAppsInTerminal": 0,
            "NumLinesOnDisplay": 0,
            "HardwareInceptionDate": "0001-01-01T00:00:00",
            "Success": false,
            "ResponseCode": "PF",
            "ResponseText": "PINpad Offline      "        
        }
    }
    
    Field KeyName Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    AIIC The AIIC that is configured in the terminal.
    NII The NII that is configured in the terminal.
    CatId The Terminal ID configured in the PIN pad
    CaId The Merchant ID configured in the PIN pad
    Timeout The bank response timeout that is configured in the terminal
    LoggedOn Indicates if the PIN pad is currently logged on
    PinPadSerialNumber The serial number of the terminal
    PinPadVersion PIN pad software version
    BankCode the bank acquirer code
    BankDescriptionBankDescription the bank description
    KVC Key Verification Code
    SAFCount Current number of stored transactions
    NetworkType The Acquirer communications type
    HardwareSerial The hardware serial number
    RetailerName The Merchant retailer name
    OptionFlags PIN pad terminal supported option flags
    SAFCreditLimit Store-and-forward credit limit
    SAFDebitLimit Store-and-forward debit limit
    MaxSAF The maximum number of store transaction
    KeyHandlingScheme The terminal key handling scheme
    CashoutLimit The maximum cash out limit
    RefundLimit The Maximum refund limit
    CPATVersion Card prefix table version
    NameTableVersion Card Name Table version
    TerminalCommsType The terminal to PC communications type
    CardMisreadCount The number of card mis-reads
    TotalMemoryInTerminal Number of memory pages in the PIN pad Terminal
    FreeMemoryInTerminal number of free memory pages in the PIN pad terminal
    EFTTerminalType The Type of the PIN pad
    NumAppsInTerminal Number of applications in the terminal
    NumLinesOnDisplay Number of available display lines on the terminal
    HardwareInceptionDate The date the hardware was incepted
    Success Indicates if the request was successful
    ResponseCode The response code of the request
    ResponseText The response text for the response code

    Logon

    Logon request

    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/$(uuidgen)/logon?async=false" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json' \
      -d '{
            "request": {
              "logonType": " "
            }
          }'  
    
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var requestContent = new
    {
        Request = new
        {
            LogonType = " "
        }
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{Guid.NewGuid().ToString()}/logon?async=false")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import uuid
    import requests; # http://python-requests.org
    
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    request_payload = {
        'request': {
            'logonType': ' '
        }
    }
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + str(uuid.uuid4()) + '/logon?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.post(uri, json=request_payload, headers=headers)
    response_payload = response.json()
    

    Instruct the EFT-Client to send a logon request to the PIN pad.

    URI Path

    POST ~/v1/sessions/<<sessionid>>/logon

    URI Query Parameters

    Parameter Value
    async 'true' for asynchronous mode, 'false' for synchronous mode

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Logon Request Object

    Example logon request object

    
    
    {
        "Request": {
            "Merchant": "00",
            "LogonType": " ",
            "Application": "00",
            "ReceiptAutoPrint": "0",
            "CutReceipt": "0"
        },
            "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field KeyName Required Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Application Indicates where the request is to be sent to. Defaults to "00" (EFTPOS)
    ReceiptAutoPrint string(1) Variable
    CutReceipt Indicates whether Linkly should cut receipts. Defaults to '0' (DontCut)
    LogonType see definition
    PurchaseAnalysisData Extended fields. See Purchase Analysis Data section for details

    Logon Response HTTP Status Codes

    Code Description
    200 Only for synchronous mode. The request completed and a valid response has been returned from the PIN pad. The 'success' property in the response object indicates the actual success of the transaction.
    202 Only for asynchronous mode. The request has been started. The POS should await the result in its notification postback (Asynchronous mode only). Response body will be null.
    400 Invalid request. The request has not completed successfully.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again
    404 Resource not found. The request was not submitted successfully.
    408 A transient error has occurred. The POS should allow the operator to try the request again.
    500-599 A server error has occurred. The POS should allow the operator to try the request again.

    Logon Response Object

    Example logon response object

    {
        "SessionId": "74a5505913df3ecd53d45930a82c3fd3",
        "ResponseType": "logon",
        "Response": {
            "PinPadVersion": "100800          ",
            "Success": true,
            "ResponseCode": "00",
            "ResponseText": "APPROVED            ",
            "Date": "0001-01-01T00:00:00",
            "Catid": "12345678",
            "Caid": "0987654321     ",
            "Stan": 0,
            "PurchaseAnalysisData": {}
        }
    }
    
    Field KeyName Description
    PinPadVersion PIN pad software version.
    Success Required. Indicates if the request was successful.
    ResponseCode The response code of the request
    ResponseText The response text for the response code
    Date Date and time of the response returned by the bank.
    Catid Terminal ID configured in the PIN pad
    Caid Merchant ID configured in the PIN pad
    Stan System Trace Audit Number
    PurchaseAnalysisData Extended fields. See Purchase Analysis Data section for details

    Settlement

    Settlement request

    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/$(uuidgen)/settlement?async=false" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json' \
      -d '{
            "request": {
              "settlementType": "S"
            }
          }'  
    
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var requestContent = new
    {
        Request = new
        {
            SettlementType = "S"
        }
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{Guid.NewGuid().ToString()}/settlement?async=false")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import uuid
    import requests; # http://python-requests.org
    
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    request_payload = {
        'request': {
            'settlementType': 'S'
        }
    }
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + str(uuid.uuid4()) + '/settlement?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.post(uri, json=request_payload, headers=headers)
    response_payload = response.json()
    

    Send a settlement request.

    URI Path

    POST ~/v1/sessions/<<sessionid>>/settlement

    URI Query Parameters

    Parameter Value
    async 'true' for asynchronous mode, 'false' for synchronous mode

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Settlement Request Object

    Example settlement request object

    {
        "Request": {
            "Merchant": "00",
            "SettlementType": "S",
            "Application": "00",
            "ReceiptAutoPrint": "0",
            "CutReceipt": "0"
        },
            "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field KeyName Required Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Application Indicates where the request is to be sent to. Defaults to "00" (EFTPOS)
    SettlementType Type of settlement to perform. Defaults to 'S' (Settlement)
    ReceiptAutoPrint string(1) Variable
    CutReceipt Indicates whether Linkly should cut receipts. Defaults to '0' (DontCut)
    ResetTotals Reset totals after settlement. Only used for settlement type 'H' (SubShiftTotals). Defaults to false

    Settlement Reponse HTTP Status Codes

    Code Description
    200 Only for synchronous mode. The request completed and a valid response has been returned from the PIN pad. The 'success' property in the response object indicates the actual success of the transaction.
    202 Only for asynchronous mode. The request has been started. The POS should await the result in its notification postback (Asynchronous mode only). Response body will be null.
    400 Invalid request. The request has not completed successfully.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again
    404 Resource not found. The request was not submitted successfully.
    408 A transient error has occurred. The POS should allow the operator to try the request again.
    500-599 A server error has occurred. The POS should allow the operator to try the request again.

    Settlement Response Object

    Example settlement response object

    
    {
        "SessionId": "7a2c33ce29b985f52f2bab7dfa4cce7d",
        "ResponseType": "settlement",
        "Response": {
            "Merchant": "00",
            "SettlementData": "000000002138VISA                000000100001000000100001000000100001+000000300003DEBIT               000000100001000000100001000000100001+000000300003069TOTAL               000000300001000000300001000000300001+000000900009",
            "Success": true,
            "ResponseCode": "00",
            "ResponseText": "APPROVED            "
        }
    }
    
    Field KeyName Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Success Required. Indicates if the request was successful.
    ResponseCode The response code of the request
    ResponseText The response text for the response code
    SettlementData Settlement Data returned from the bank

    QueryCard

    Query card request

    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/$(uuidgen)/querycard?async=false" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json' \
      -d '{
            "request": {
              "queryCardType": "0"
            }
          }'  
    
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var requestContent = new
    {
        Request = new
        {
            QueryCardType = "0"
        }
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{Guid.NewGuid().ToString()}/querycard?async=false")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import uuid
    import requests; # http://python-requests.org
    
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    request_payload = {
        'request': {
            'queryCardType': '0'
        }
    }
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + str(uuid.uuid4()) + '/querycard?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.post(uri, json=request_payload, headers=headers)
    response_payload = response.json()
    

    Send a query card request.

    URI Path

    POST ~/v1/sessions/<<sessionid>>/querycard

    URI Query Parameters

    Parameter Value
    async 'true' for asynchronous mode, 'false' for synchronous mode

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Query Card Request Object

    Example querycard request object

    {
        "Request": {
            "Merchant": "00",
            "QueryCardType": "0",
            "Application": "00"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field KeyName Required Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Application Indicates where the request is to be sent to. Defaults to "00" (EFTPOS)
    QueryCardType Type of querycard to perform. Defaults to '0'
    PurchaseAnalysisData Extended fields. See Purchase Analysis Data section for details

    Query Card Response HTTP Status Codes

    Code Description
    200 Only for synchronous mode. The request completed and a valid response has been returned from the PIN pad. The 'success' property in the response object indicates the actual success of the transaction.
    202 Only for asynchronous mode. The request has been started. The POS should await the result in its notification postback (Asynchronous mode only). Response body will be null.
    400 Invalid request. The request has not completed successfully.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again
    404 Resource not found. The request was not submitted successfully.
    408 A transient error has occurred. The POS should allow the operator to try the request again.
    500-599 A server error has occurred. The POS should allow the operator to try the request again.

    Query Card Response Object

    Example querycard response object

    {
      "sessionId": "7a2c33ce29b985f52f2bab7dfa4cce7d",
      "responseType": "querycard",
      "response": {
        "merchant": "00",
        "isTrack1Available": false,
        "isTrack2Available": true,
        "isTrack3Available": false,
        "track1": "",
        "track2": "1234567890=0949?,,S, YES, 05???????\u0000",
        "track3": "",
        "cardName": "32",
        "accountType": " ",
        "success": true,
        "responseCode": "00",
        "responseText": "APPROVED            ",
        "purchaseAnalysisData": {}    
      }
    }
    
    Field KeyName Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Success Required. Indicates if the request was successful.
    ResponseCode The response code of the request
    ResponseText The response text for the response code
    AccountType Account type selected
    isTrack1Available Indicates if track1 was read
    isTrack2Available Indicates if track2 was read
    isTrack3Available Indicates if track3 was read
    Track1 Data encoded on track1 of the card
    Track2 Data encoded on track2 of the card
    Track3 Data encoded on track3 of the card
    CardName The BIN number of the card
    PurchaseAnalysisData Extended fields. See Purchase Analysis Data section for details

    ConfigureMerchant

    Configure merchant request

    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/$(uuidgen)/configuremerchant?async=false" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json' \
      -d '{
            "request": {
              "catid": "12345678",
              "caid": "0123456789ABCDE"
            }
          }'  
    
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var requestContent = new
    {
        Request = new
        {
            Catid = "12345678",
            Caid = "0123456789ABCDE"
        }
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{Guid.NewGuid().ToString()}/configuremerchant?async=false")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import uuid
    import requests; # http://python-requests.org
    
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    request_payload = {
        'request': {
            'Catid': '12345678',
            'Caid': '0123456789ABCDE'
        }
    }
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + str(uuid.uuid4()) + '/configuremerchant?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.post(uri, json=request_payload, headers=headers)
    response_payload = response.json()
    

    Send a configure merchant request.

    URI Path

    POST ~/v1/sessions/<<sessionid>>/configuremerchant

    URI Query Parameters

    Parameter Value
    async 'true' for asynchronous mode, 'false' for synchronous mode

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Configure Merchant Request Object

    Example configure merchant request object

    {
        "Request": {
            "Merchant": "00",
            "Catid": "12345678",
            "Caid": "0123456789"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field KeyName Required Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Application Indicates where the request is to be sent to. Defaults to "00" (EFTPOS)
    Catid The terminal ID (CatID) to configure the terminal with
    CaId The merchant ID (CaID) to configure the terminal with
    AIIC The AIIC to configure the terminal with. Defaults to 0
    NII The NII to configure the terminal with. Defaults to 0
    Timeout The bank response timeout specified in seconds. Defaults to 45

    Configure Merchant Response HTTP Status Codes

    Code Description
    200 Only for synchronous mode. The request completed and a valid response has been returned from the PIN pad. The 'success' property in the response object indicates the actual success of the transaction.
    202 Only for asynchronous mode. The request has been started. The POS should await the result in its notification postback (Asynchronous mode only). Response body will be null.
    400 Invalid request. The request has not completed successfully.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again
    404 Resource not found. The request was not submitted successfully.
    408 A transient error has occurred. The POS should allow the operator to try the request again.
    500-599 A server error has occurred. The POS should allow the operator to try the request again.

    Configure Merchant Response Object

    Example configure merchant response object

    {
      "sessionId": "7a2c33ce29b985f52f2bab7dfa4cce7d",
      "responseType": "configuremerchant",
      "response": {
        "merchant": "00",
        "success": true,
        "responseCode": "00",
        "responseText": "APPROVED            "
      }
    }
    
    Field KeyName Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Success Required. Indicates if the request was successful.
    ResponseCode The response code of the request
    ResponseText The response text for the response code

    Reprint Receipt

    Reprint receipt request

    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/$(uuidgen)/reprintreceipt?async=false" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json' \
      -d '{
            "request": {
              "reprintType": "2"
            }
          }'  
    
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var requestContent = new
    {
        Request = new
        {
            ReprintType = "2"
        }
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{Guid.NewGuid().ToString()}/reprintreceipt?async=false")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import uuid
    import requests; # http://python-requests.org
    
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    request_payload = {
        'request': {
            'reprintType': '2'
        }
    }
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + str(uuid.uuid4()) + '/reprintreceipt?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.post(uri, json=request_payload, headers=headers)
    response_payload = response.json()
    

    Send a reprint receipt request.

    URI Path

    POST ~/v1/sessions/<<sessionid>>/reprintreceipt

    URI Query Parameters

    Parameter Value
    async 'true' for asynchronous mode, 'false' for synchronous mode

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Reprint Receipt Request Object

    Example reprint receipt request object

    {
        "Request": {
            "Merchant": "00",
            "Application": "00",
            "ReceiptAutoPrint": "0",
            "ReprintType": "2"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    
    Field KeyName Required Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Application Indicates where the request is to be sent to. Defaults to "00" (EFTPOS)
    ReceiptAutoPrint string(1) Variable
    CutReceipt Indicates whether Linkly should cut receipts. Defaults to '0' (DontCut)
    ReprintType Indicates whether the receipt should be returned or reprinted. Defaults to '2' (GetLast) '1' is Reprint
    OriginalTxnRef The original txnRef of the transaction
    PurchaseAnalysisData Extended fields. See Purchase Analysis Data section for details

    Reprint Receipt Response HTTP Status Codes

    Code Description
    200 Only for synchronous mode. The request completed and a valid response has been returned from the PIN pad. The 'success' property in the response object indicates the actual success of the transaction.
    202 Only for asynchronous mode. The request has been started. The POS should await the result in its notification postback (Asynchronous mode only). Response body will be null.
    400 Invalid request. The request has not completed successfully.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again
    404 Resource not found. The request was not submitted successfully.
    408 A transient error has occurred. The POS should allow the operator to try the request again.
    500-599 A server error has occurred. The POS should allow the operator to try the request again.

    Reprint Receipt Response Object

    Example reprint receipt response object

    {
      "sessionId": "7a2c33ce29b985f52f2bab7dfa4cce7d",
      "responseType": "reprintreceipt",
      "response": {
        "merchant": "00",
        "receiptText": [
                "------------------------",
                " *** TRAINING MODE ***  ",
                "  TEST MERCHANT TITLE   ",
                "   TEST MERCHANT NAME   ",
                "         LINE2          ",
                "                        ",
                "14:45:52 03/08/18       ",
                "                        ",
                "CREDIT ACCOUNT          ",
                "                        ",
                "PURCHASE   AUD     $1.00",
                "                --------",
                "TOTAL      AUD     $1.00",
                "                        ",
                "APPROVED -  00          ",
                "                        ",
                "PLEASE RETAIN AS RECORD ",
                "      OF PURCHASE       ",
                "------------------------"
            ],
        "success": true,
        "responseCode": "00",
        "responseText": "APPROVED            "
      }
    }
    
    Field KeyName Description
    Merchant Two Digit Merchant Code. Defaults to "00" (EFTPOS)
    Success Required. Indicates if the request was successful.
    ResponseCode The response code of the request
    ResponseText The response text for the response code
    ReceiptText Receipt text to be printed. Returned as an array of lines

    Send Key

    Send a key press from the POS to an existing active session.

    # replace <<uuid>> with the uuid from your transaction request
    # replace <<token>> with the token returned from your auth request
    curl -v "https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/<<uuid>>/sendkey?async=false" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer <<token>>' \
      -H 'Accept: application/json' \
      -d '{
            "request": {
              "key": "0"
            }
          }'  
    
    var token = "<<token>>"; // replace <<token>> with the token returned from your auth request
    var uuid = "<<uuid>>"; // replace <<uuid>> with the uuid your transaction request
    var requestContent = new
    {
        Request = new
        {
            Key = "0"
        }
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/{uuid}/sendkey?async=false")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import datetime
    import requests; # http://python-requests.org
    
    uuid = '<<uuid>>' # replace <<uuid>> with the uuid from your transaction request
    token = '<<token>>' # replace <<token>> with the token returned from your auth request
    request_payload = {
        'request': {
            'key': '0'
        }
    }
    uri = 'https://rest.pos.sandbox.cloud.pceftpos.com/v1/sessions/' + uuid + '/sendkey?async=false'
    headers = {'Authorization': 'Bearer ' + token}
    response = requests.post(uri, json=request_payload, headers=headers)
    response_payload = response.json()
    

    Send a key press request.

    URI Path

    POST ~/v1/sessions/<<sessionid>>/sendkey

    URI Query Parameters

    Parameter Value
    async 'true' for asynchronous mode, 'false' for synchronous mode

    Headers

    Parameter Value
    Authorization The bearer token returned from ~/v1/tokens/cloudpos
    Content-Type application/json
    Accept application/json

    Send Key Request Object

    Example send key request object

    {
        "Request": {
            "Key": "0",
            "Data": ""
        }
    }
    
    Field KeyName Required Description
    Key true Indicates the key to be pressed.
    '0' for the CANCEL key or OK key (see Note 1)
    '1' for the YES key
    '2' for the NO key
    '3' for the AUTH key
    Data Entry data collected by POS. Maximum length of 60 characters

    Note 1:
    The OK and CANCEL key are the same key. Only one can be displayed at a time.

    Send Key Response HTTP Status Codes

    Code Description
    200 Only for synchronous mode. The request completed and a valid response has been returned from the PIN pad. The 'success' property in the response object indicates the actual success of the transaction.
    202 Only for asynchronous mode. The request has been started. The POS should await the result in its notification postback (Asynchronous mode only). Response body will be null.
    400 Invalid request. The request has not completed successfully.
    401 The token supplied is invalid. The POS should refresh the token and attempt the request again
    404 Resource not found. The request was not submitted successfully.
    408 A transient error has occurred. The POS should allow the operator to try the request again.
    500-599 A server error has occurred. The POS should allow the operator to try the request again.

    Send Key Response Object

    Example send key response object

    {
      "sessionId": "7a2c33ce29b985f52f2bab7dfa4cce7d",
      "responseType": "sendkey",
      "response": null
    }
    

    Notifications

    This section contains all the responses that return to the POS if its using async mode. This does not cover the response to the original requests.

    Display Response

    Example display response object

    {
        "SessionId": "3a3cff3bf4cfe3bf59a5f442d5f40496",
        "ResponseType": "display",
        "Response": {
            "NumberOfLines": 2,
            "LineLength": 20,
            "DisplayText": [
                "     SWIPE CARD     ",
                "                    "
            ],
            "CancelKeyFlag": true,
            "AcceptYesKeyFlag": false,
            "DeclineNoKeyFlag": false,
            "AuthoriseKeyFlag": false,
            "OKKeyFlag": false,
            "InputType": "0",
            "GraphicCode": "3",
            "PurchaseAnalysisData": {}
        }
    }
    
    Field KeyName Description
    NumberOfLines The number of lines to display
    LineLength Line length of the display
    DisplayText Array of strings, containing each line to display
    CancelKeyFlag if the cancel button is available
    AcceptYesKeyFlag if the accept/yes button is available
    AuthoriseKeyFlag if the authorise button is available
    OKKeyFlag if the OK button is available
    InputType Type of input requested by the PIN pad. See input type table below for details
    GraphicCode Type of graphics to display. See graphics code table below for details
    PurchaseAnalysisData Extended fields. See Purchase Analysis Data section for details
    Graphics Code Description
    0 Processing
    1 Verify
    2 Question
    3 Card entry
    4 Account entry
    5 PIN entry
    6 Complete
    Input Type Description
    0 Input disabled
    1 Normal ASCII input
    2 Formatted amount entry ($0.cc)
    3 2 decimal place formatted entry without dollar sign
    4 Masked Password entry
    5 Supervisor Request from PIN pad
    6 One key input from POS. As soon as one key is pressed on the POS, the key is sent to the PIN pad

    Receipt Response

    Example receipt response object

    {
        "SessionId": "3a3cff3bf4cfe3bf59a5f442d5f40496",
        "ResponseType": "receipt",
        "Response": {
            "Type": "C",
            "ReceiptText": [
                "------------------------",
                " *** TRAINING MODE ***  ",
                "  TEST MERCHANT TITLE   ",
                "   TEST MERCHANT NAME   ",
                "         LINE2          ",
                "                        ",
                "10:20:19 06/08/18       ",
                "                        ",
                "CREDIT ACCOUNT          ",
                "                        ",
                "PURCHASE   AUD     $1.00",
                "                --------",
                "TOTAL      AUD     $1.00",
                "                        ",
                "APPROVED -  00          ",
                "                        ",
                "PLEASE RETAIN AS RECORD ",
                "      OF PURCHASE       ",
                "------------------------"
            ],
            "IsPrePrint": false
        }
    }
    
    Field KeyName Description
    Type Type of receipt either C for customer of M for merchant, L for logon, S for settlement
    ReceiptText Array of strings, containing each line of the receipt
    IsPrePrint indicates if this response is a preprint

    Properties

    AccountType

    This property is used in both events and methods, and because of this, there needs to be careful control over the setting of this property.
    Event results for this property:

    Returned Property Description
    From a 'TransactionEvent' The Customer account type that was selected in a transaction will be returned as:
    'Cheque','Savings', 'Credit', "Account 1", "Account 2", "Account 3", "Account 4" or "Account 5".
    From a 'QueryCardEvent' It will be "0" = Savings, "2" = Cheque, "3" = Credit

    Aiic

    Acquiring Institution Identification Code.
    Returned by Status.
    Applies to configMerchant.
    Note: Not supported by all acquirers.

    AmtCash

    The amount of cash out for the transaction.
    The STG Agency Deposit function uses this property to hold the total cash amount to deposit.
    Applies to Transaction.

    AmtCreditLimit

    Credit limit amount.
    Not used - Reserved for future use.

    AmtPurchase

    The purchase amount for the transaction.
    Returned by transaction.

    AmtTip

    The tip amount for the transaction. Contains 0 if no tip was added. Returned by transaction.

    Application

    Value Description
    "00" Make EFTPOS payment
    "02" Make payment using extension

    Applies to Transaction.

    AuthCode

    Authorisation code. Returned by Transaction if the EFTPOS Acquirer returned the AuthCode field. Also required as input to DoTransaction when a Completion is being performed.
    Returned by if the acquirer returned a reference.
    Returned by Transaction
    Applies to Transaction.

    AvailableBalance

    The balance amount remaining on the card, only used on fixed value payment products.

    Caid

    Card Acceptor ID, also known as the "Merchant" ID.
    Returned by Transaction, LogonEvent, Status.
    Applies to DoConfigMerchant.

    CancelKeyFlag

    Enables / disables the availability of the cancel button on the display.

    CardType

    Indicates the card type used for the transaction as described by the bank. Examples may include: 'AMEX', 'VISA', 'DEBIT'. The possible values of this field may change between acquirers and pinpad versions. To identify the payment type used, reference the CardName field. Returned by TransactionEvent.

    CardName

    This property returns the Card BIN which can be used to identify the type of card payment used.

    Card BIN Description
    0 Unknown
    1 Debit Card
    2 China Union Pay
    3 MasterCard
    4 Visa
    5 American Express
    6 Diners Club
    7 JCB
    8 Private Label Card
    9 JCB
    10 Maestro
    11 JCB
    12 Other
    13 Cabcharge
    14 Bartercard
    15 Fuel Card
    16 Loyalty
    17 Gift Card
    18 Return Card
    19 Shop Card
    20 GE Card
    21 Non-FI Card
    22 Myer Black Card
    23 Fleet Card
    24 Motopass
    25 Motorcharge
    26 Logo 1
    27 Logo 2
    28 Visa Debit
    29 Mastercard Debit
    30 Unionpay credit
    31 Unionpay debit
    51 Wishlist
    52 GiveX
    53 Blackhawk
    54 PayPal
    55 Reserved
    56 Reserved
    57 FDI
    58 Reserved
    59 WrightExpress
    60 Reserved
    61 Reserved
    63 ePay Universal
    64 Incomm
    65 AfterPay
    66 AliPay
    67 Humm
    68 First Data Gift Card
    69 WeChat
    70 Klarna
    89 Zip Money
    90 TruRating
    98 Reserved
    99 Reserved

    Catid

    Card Acceptor Terminal ID.
    Returned by Transaction, LogonEvent, Status.
    Applies to configMerchant.

    ChqAccount

    Cheque Account Number.
    Applies to .
    NOT Used

    ChqBranch

    Cheque Branch Number.
    Applies to .
    NOT Used

    ChqSerialNumber

    Cheque Serial Number.
    Applies to .
    NOT Used

    ClearedFundsBalance

    The cleared funds balance amount.

    CommandCode

    Used to indicate what command is being passed to Linkly

    ConfigLocked

    Set to True if the PIN pad configuration parameters are locked.
    (If the terminal has stored transactions or there is a reversal pending the terminal details cannot be altered).
    NOT Used

    CurrencyCode

    Currency code for this transaction (e.g. AUD) A 3-digit ISO currency code. Defaults to " "(NotSet).

    CutReceipt

    Set to "1" if the receipt should be cut by the printer after the receipt is printed.
    "0" Don't cut

    DataField

    A private Data Field.
    - For the DisplayEvent this field contains multiple lines of text to display (usually 2 lines of 20 characters each).

    For the QueryCard Event
    It will contain the following if it was available in the PIN pad CPAT:

    Description Length
    Card Bin number 1 byte(non ascii)
    Account Grouping Code 1 byte
    Extended Service Code 1 byte
    Processing Code 1 byte
    AIIC 6 byte

    For the Transaction, this field contains the TO/FROM data when a Funds Transfer is performed.

    For the LogonEvent, this property contains a byte array of values: Currently assigned bytes are byte 0 = EFTPOS txns allowed, byte 1 = Agency txns allowed.
    The array will be in the following order:

    Index Content
    0 Settlement
    1 Pre-Settlement
    2 Last-Settlement
    3 Sub-Totals
    4 Terminal Shift Totals
    5 Reserved
    6 Transaction Listing
    7 SAF Totals
    8 Mini-Statement
    9 Detailed Cash Statement (STG Agency)
    10-15 Reserved

    For the Status, this field will contain the Extra Status information which is used in PX328 Linkly systems and onward.
    For a Transaction Request, if the TxnType is set to "K", this property will contain data for the PIN pad to use in processing the Enhanced PIN command.
    This data is in the following format when the MessageType = "0" (status):

    Name Length Description
    SAF Count 4 SAF Count (if PIN pad has a SAF)
    Network Type 1 '1' = Leased, '2' = Dial-up
    Hardware Serial # 16 Actual Serial Number that is unique to the h/w
    Retailer Name 40 AS2805 Field 43 (if supported by host)
    Options Flags 32 These flags denote the support of various options within the terminal.
    Stand in Credit card Limit 9 Max limit allowed for stand-in on credit cards
    Stand in Debit card limit 9 Max Limit allowed for stand-in on debit cards
    Max number of stand-in transactions 3
    Key-handling scheme 1 '0' = Single DES '1' = Triple DES
    Maximum Cash Out Limit 9 $$$$$$$cc
    Maximum Refund Limit 9 $$$$$$$cc
    Current CPAT version 6
    Current Name table version 6
    Terminal Comms Type 1 '0' = Cable, '1' = Infra-red
    Card Misread Count 6
    Total # memory pages 4
    # free memory pages 4
    EFT Terminal Type 4
    # applications in terminal 2
    # lines on terminal display 2
    Hardware inception Date 6 DDMMYY - Date that the hardware serial number was entered into this device.

    Supported Functionality Index:

    Byte Description
    0 Tipping
    1 Pre-Auth
    2 Completions
    3 Cash-Out
    4 Refund
    5 Balance Enquiries
    6 Deposits
    7 Voucher Entry
    8 MOTO Transactions
    9 Auto Completions
    10 Electronic Fallback
    11 EMV
    12 Training Mode
    13 Withdrawal
    14 Funds Transfer
    15 Start Cash

    The Data in the following format is for MessageType = '1' (Terminal Info)

    Name Byte Description
    Eprom Type 1 'Y' = 1Mb, 'X' = 2Mb
    Terminal Type 2
    OS Version 2
    OS CRC 4
    BIOS Version 2
    BIOS CRC 4
    # Free Pages 3
    # Applications 2

    For each application in the terminal the following will be present:

    Name Byte
    Application Number 2
    Application Version 2
    Active Flag 1
    Corrupted Flag 1
    Number of code pages 2
    CRC for each code page #pages * 2
    Number of data pages

    The Data in the following format is for MessageType = '2' (CPAT)

    Name Byte
    CPAT Version # 6
    # Offline Transactions allowed 3
    #card prefix entries 3

    For each CPAT entry, the following will be sent:

    Name Byte Description
    Prefix 10
    Card Index 2
    Card Bin# 2
    Account Grouping Code 1
    AIIC 11
    Processing Code 2
    DB card limit 6
    CR card limit 6
    ESC flag 1 Indicated if the Extended Service code table is to be used for this card.

    • The data is in the following format for MessageType = '3' (card name table)

    Name Byte
    Card Table version # 6
    # card prefix entries 3

    For each card name entry, the following will be sent:

    Name Byte
    Card Name 20
    Bin # 2
    Index 2

    • The Data is in the following format for MessageType = "4" (Offline Txns)

    Name Byte
    Reversal Present 1 True if the reversal is present in the SAF. The first entry will be the reversal. The remainder will be the SAF transactions.
    Number of entries 3

    For each entry in the SAF, the following will be present:

    Name Byte
    Processing Code 6
    Transaction Amount 12
    Transmission Date/Time 2 MMDDhhmmss
    POS entry mode 3
    Card Seq # 3
    Track2 Details 40 "card data", '=', "expiry date", "pad with end sentinels (?)"
    RRN 12
    Auth # 6
    Cash Out Amount 12

    Date

    Date of transaction
    Returned by Transaction

    DateExpiry

    Set before calling Transaction if a customer's card details are manually entered by the operator.
    Used in conjunction with the Pan property.
    Returned by Transaction.
    Applies to Transaction.

    DateSettlement

    Contains the settlement date for the transaction in 'DDMMYYYY' format.
    Used as input to Settlement with certain EFTPOS acquirers to specify the date for which the settlement details are to be retrieved.
    In this case DateSettlement should be blank if the current days totals are to be retrieved.
    Returned by Transaction and Settlement
    Applies to Settlement.

    DisplayText

    An array of strings containing the text to display.

    EftPosNetwork

    Indicates the network to which the PIN pad is connected.
    Returned by Status.

    EnableTip

    Set before calling Transaction. If EnableTip is True before calling Transaction, the customer receipt will have an area for a TIP to be entered. The POS should store all details related to Tip Adjustments, so that the POS can send the tip adjustment to the Linkly system with the Transaction method (with TxnType = "T").
    Applies to Transaction.
    Note: Not supported by all acquirers.

    InputData

    The Input Data that is returned if the POS is implementing a custom display with Input using the Display Request, maximum 20 characters. 

    InputDataFieldKey

    Note 1: This tag is set if the Authorise Key Flag is set. the Input Field Key values can be: - '1'= Normal ASCII input - '2'= Formatted Amount entry ($0.cc) - '3'= 2 decimal place formatted entry without dollar sign - '4'= Masked Password entry - '5'= Supervisor Request from pinpad - '6'= One key input from POS. As soon as one key is pressed on the POS, the key is sent to the pinpad It is mandatory that a POS support option '1' for this key type

    KeyPressed

    Indicates which key is to be pressed '0' for the CANCEL key '1' for the YES key '2' for the NO key '3' for the AUTH key

    KVC

    This property is used to hold the CVV (card verification value ) of the magnetic card stripe. This field is not mandatory.

    LastTxnSuccess

    Set to True if the last transaction was successful.
    Returned by GetLastTransaction.

    LineLength

    The length of the lines in the display.

    LoggedOn

    Set to True if the PIN pad is in a logged on state, False if a logon is required. It is never necessary for an application to use DoLogon to explicitly logon a PIN pad as auto-logons are performed.
    Returned by Status.

    LogonType

    The type of logon to perform.

    Value Description
    " " Standard
    "4" RSA logon
    "5" TMSFull
    "6" TMSParams
    "7" TMSSoftware
    "8" Logoff
    "1" Diagnostics

    Merchant

    Indicates the active merchant. (Reserved for future use) - Currently only merchant 0 is supported and setting this property to any other value will result in an error.

    Value Description
    "00" Default value to indicate EFTPOS
    "65" AfterPay payment
    "66" Alipay payment
    "67" Humm payment
    "89" ZipMoney payment

    Applies to Transaction, Logon, Settlement, and Status.

    MessageType

    A property to represent:
    - The Message type returned by Transaction.
    - The Subcode to select in a Status request.
    - The resulting subcode in a Status

    Nii

    EFTPOS Network International Identifier.
    Returned by Status.
    Applies to ConfigMerchant.
    Note: Not supported by all acquirers.

    NumberOfLines

    The number of lines in the display.

    OkKeyFlag

    Enables / disables the availability of the OK button on the display.

    Pan

    Primary Account Number. Loaded with the customer PAN for manually entered transactions.
    Only credit card details may be entered manually. Refer also to the properties DateExpiry, and PanSource.
    Returned by Transaction (return format is acquirer dependent any may be in short 6...3 format).
    Applies to Transaction.

    PanSource

    Indicates the source of the customer card details. The following values are valid for PanSource:

    Value Description
    ' ' (Space) PIN pad will read card using internal card reader
    'K' Manual Entry of card details using DateExpiry and Pan properties
    'S' Track2 property contains application supplied card details read directly form a magnetic stripe reader (MSR)

    The following additional options are only used in MOTO (mail order/telephone order systems) where the pan source is a manually entered card. Use the above 'K' option for all other manual card options.

    Value Description
    '0' Internet originated transaction
    '1' Telephone originated transaction
    '2' Mail order originated transaction
    '3' Customer present
    '4' Recurring transaction
    '5' Installment

    Applies to Transaction.

    PinPadPort

    The port to which the PIN pad is attached. On input, this property may be used to set the specific PIN pad port to use. On output, it indicates the PIN pad port used for the transaction.
    Applies to Transaction, Logon, Settlement
    Note: Not supported by all acquirers.

    PinPadSerialNumber

    The hardware ID or Serial Number of the attached PIN pad.
    Returned by StatusEvent.

    PinPadVersion

    The PIN pad software name and version (Up to 16 characters).
    Returned by Status

    PHN

    Humm only. Customer phone number. Applies to Humm Invite

    QueryCardType

    The type of query to perform during a QueryCard request

    Value Description
    "0" Read card only
    "1" read card + select account
    "5" select account only
    "7" pre-swipe
    "8" Preswipe special

    Receipt

    Formatted EFTPOS receipt information (Up to 2048 characters).
    Returned by PrintReceipt, GetLastReceipt.

    ReceiptAutoPrint

    ReceiptAutoPrint Description
    "0" Return all receipts to the POS in a receipt event. Only supported when async=true
    "1" Not supported in the REST API
    "7" Print all merchant/signature receipts from the PINpad printer, return all other receipts to the POS in the transaction/logon/settlement response
    "9" Print all receipts from the PINpad printer

    ResetTotals

    This property should be set to True if the current totals should be reset when calling Settlement
    with TxnType of shift Totals.
    Applies to Settlement.

    ResponseCode

    A 2 character code returned by the bank indicating the result of the transaction.
    Returned by all events.

    ResponseText

    A textual description of the bank response code (up to 20 characters).
    Returned by all events.

    ResponseType

    The type of response that is being returned. This can be used to help sort responses sent to POS postback endpoints.

    ResponseType
    transaction
    logon
    settlement
    status
    querycard
    configuremerchant
    reprintreceipt
    display
    receipt

    RRN

    Retrieval Reference Number this value is used to trace transactions.

    SettleCardTotals

    Ascii records containing settlement data for each card type settled. The ascii card records are defined as follows:

    Length Description
    20 Card Name
    9 Purchase Amount
    3 Purchase Count
    9 Cash-Out Amount
    3 Cash-Out Count
    9 Refund Amount
    3 Refund Count
    1 Totals sign (+ or -)
    9 Totals Amount
    3 Totals Count

    Returned by Settlement.

    SettlementType

    Value Description
    "S" Settlement
    "P" Pre-Settlement
    "L" Last Settlement
    "U" Sub Totals or Summary Totals for ANZ
    "H" Shift Totals or Subtotals for ANZ
    "I" Txn Listing
    "M" Start Cash
    "F" Store and forward (SAF) totals report
    "D" Daily cash statement (STG Agency)

    Stan

    The Systems Trace Audit Number of the last transaction performed. (0-999999).
    Returned by Transaction, GetLastTransaction, Logon.

    StatusType

    The type of status to perform

    Value Description
    "0" Standard
    "1" TerminalAppInfo
    "2" AppCPAT
    "3" AppNameTable
    "4" Undefined
    "5" Preswipe

    SubCode

    Used to control behavor of methods:

    Reprint receipt Indicates to reprint or retrieve (sent to POS)

    Get last transaction

    Success

    Boolean value indicating success or failure of relevant event/method call. eg. If the request was of type transaction, this flag indicates that the financial transaction (sale) succeeded. Returned by all events.

    Time

    Transaction time returned by the acquirer. 'HHMMSS' format.
    Returned by Transaction, Logon.

    Timeout

    EFTPOS transaction timeout. Determines the maximum amount of time that the PIN pad will wait for a reply from the EFTPOS network. Value is from 10-255 seconds.
    Returned by Status.
    Applies to ConfigMerchant.
    Note: Not all acquirers support modification of this value.

    TotalsData

    A totals record containing the locally stored terminal totals.

    Length Description
    20 Totals Description
    9 Purchase Amount
    3 Purchase Count
    9 Cash-out amount
    3 Cash-out count
    9 Refund Amount
    3 Refund Count
    1 Total Sign
    9 Total Amount
    3 Total Count

    For a Mini Statement or a Store and Forward totals message, this field will contain the data sent back in those responses as defined by the bank.
    For a Settlement with a txntype of "A" (Daily Cash Statement), this field will contain data to be sent to the terminal. The format of this data is up to the terminal application that needs the data.

    For each charge card:

    Length Description
    11 Card Name
    02 Totals bin
    03 Credit count
    09 Credit amount
    03 Debit count
    09 Debit amount
    09 Net amount

    Note: there is only one base record, but the number of charge cards is variable.

    Returned by Settlement.

    Track1

    Contents of magnetic card track 1 or 3, if either is read by the PIN pad.
    Returned by QueryCard.

    TotalPurchaseCount

    The total number of cheques that are to be processed by a STG Agency terminal Deposit function.
    Applies to: Transaction.

    Track2

    Contents of magnetic card track 2. This property should be loaded by the application prior to calling Transaction if the customer card is read by an application Magnetic Stripe Reader.
    QueryCard returns the contents of track 2 for any card. The format of this field is acquirer dependent any may be in shorted format.
    Returned by Transaction, QueryCard.
    Applies to Transaction.

    TxnFlags

    The transaction flags that apply to the transaction

    TxnRef

    Application supplied reference number up to 16 characters in length. TxnRef can contain any ascii characters between 32 and 127 (decimal).

    Returned by Transaction, GetLastTransaction.
    Applies to Transaction.

    TxnType

    This property should be set to indicate the type of transaction to be performed when calling Transaction or Settlement.
    See Appendix E - Txn type.

    Value Added Applications

    One Button

    Overview

    The Linkly One button offers a simple entry point for POS developers to send transactions to Linkly supported third party payment applications.

    Customers will still need to support each payment type, and have it enabled within the Linkly environment for One button to work.

    Instead of needing to implement different transaction types for different applications, the POS need only implement this one. This API requires knowledge of the Linkly Basket.

    When a purchase is sent to Merchant 99, the PIN pad will display a menu asking the customer to select which payment type they would like to use for the transaction.

    For example, if the merchant has Afterpay, Alipay, and Humm enabled will have the following menu options:

    Payment Type

    1. Afterpay
    2. Alipay
    3. Humm

    The customer is then able to select which payment option to use.

    Payment supported by the One Button API:

    Prerequisites

    The One Button API is based on the Core Payments API and requires the POS to implement the same minimum requirements.

    Onboarding

    Each AppHub product requires a set of credentials to identify and authorise the merchant on the third party's platform. These credentials range from username/password to one-time activation keys and are normally entered manually into the local registry or via a Linkly provided installer. The process for onboarding via Connect is as follows:

    1. Merchant gets credentials from the third party
    2. Linkly register merchant in Cloud Portal as instore or cloud customer
    3. Merchant enters ActivationCode into their lane
    4. Linkly perform activation process on customer's AppHub products
    5. Linkly deploy and configure selected AppHub products to customer's lane
    6. Merchant can now perform AppHub sales.

    Transaction Types

    Supported Transaction Types

    The One Button API provides the following transactional types across AppHub products:

    Transaction Types

    Management of merchant/bank functions

    Transactional Scenarios

    Error Handling

    Purchase

    Example One Button purchase request object

    {
        "Request": 
        {
            "Merchant": "99",
            "TxnType": "P",
            "AmtPurchase": 100,     
            "TxnRef": "1234567890",
            "CurrencyCode": "AUD",      
            "CutReceipt": "0",
            "ReceiptAutoPrint": "0",
            "Application": "02",
            "PurchaseAnalysisData":
            {
                "OPR": "00766|test",
                "AMT": "0042000",
                "PCM": "0000"
            },
            "Basket": 
            {  
                "id": "t39kq18134553",  
                "amt": 2145,  
                "tax": 200,  
                "dis": 50,  
                "sur": 0,  
                "items": [{  
                    "id": "t39kq002",  
                    "sku": "k24086723",  
                    "qty": 2,  
                    "amt": 2145,  
                    "tax": 200,  
                    "dis": 50,  
                    "name": "XData USB Drive"  
                }]  
            } 
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Purchase Request

    To call the One Button purchase request, make a Core Payments purchase request with Merchant "99" and Application "02".

    Example One Button purchase response object

    {
        "SessionId": "dd250a0c81c202b66220d7379b338b8f",
        "ResponseType": "transaction",
        "Response": {
            "TxnType": "P",
            "Merchant": "61",
            "CardType": "AMEX CARD           ",
            "CardName": "05",
            "RRN": "123456789012",
            "DateSettlement": "2018-07-31T00:00:00",
            "AmtCash": 0,
            "AmtPurchase": 100,
            "AmtTip": 0,
            "AuthCode": 123456,
            "TxnRef": "1234567890      ",
            "Pan": "37601234567890      ",
            "DateExpiry": "4909",
            "Track2": "37601234567890=0949?,,S, YES, 05??????  ",
            "AccountType": "2",
            "TxnFlags": {
                "Offline": "1",
                "ReceiptPrinted": "0",
                "CardEntry": "S",
                "CommsMethod": "0",
                "Currency": "0",
                "PayPass": "0",
                "UndefinedFlag6": "0",
                "UndefinedFlag7": "0"
            },
            "BalanceReceived": false,
            "AvailableBalance": 0,
            "ClearedFundsBalance": 0,
            "Success": true,
            "ResponseCode": "00",
            "ResponseText": "APPROVED            ",
            "Date": "2018-07-31T16:14:40",
            "Catid": "12345678",
            "Caid": "0987654321     ",
            "Stan": 0,
            "PurchaseAnalysisData": {
              "RFN": "klujhadsc9ph87asd",
              "REF": "12345",
              "HRC": "ERR1",
              "HRT": "INVALID CARD"
            }
        }
    }
    

    Purchase Response

    The CardName and Merchant properties in the response will indicate the payment type selected.

    Refund

    Example One Button refund request object

    {
        "Request": 
        {
            "Merchant": "99",
            "TxnType": "R",
            "AmtPurchase": 100,     
            "TxnRef": "1234567890",
            "CurrencyCode": "AUD",      
            "CutReceipt": "0",
            "ReceiptAutoPrint": "0",
            "Application": "02",
            "PurchaseAnalysisData":
            {
                "RFN": "klujhadsc9ph87asd",
                "OPR": "00766|test",
                "AMT": "0042000",
                "PCM": "0000"
            }
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Refund Request

    To call the One Button refund request, make a Core Payments refund request with Merchant "99" and Application "02".

    Refund Response

    The refund response is in the format of the transaction response object, see the Transaction section for a detailed breakdown.

    The CardName and Merchant properties in the response will indicate the payment type used for the refund.

    Management Functions

    The POS should implement: * Reprint Receipt from the Linkly Core Payments management functions with Merchant "99" and Application "02". * Transaction Status from Linkly Core Payments management functions

    Error Handling

    The POS should implement error handling as outlined by the Error recovery section.

    Third Party payment barcode/QR code timeout

    The table below lists how long the bar code or QR code from the payment provider is valid for once it's generated by the customer.

    Third Party Payment Method Timeout
    ZipMoney Barcode 5 minutes
    AfterPay Barcode 10 minutes
    Alipay QR Code Unknown
    WeChat QR Code Unknown
    Humm Barcode 5 minutes
    Klarna QR Code 2 minutes

    Optional Functionality

    Custom Displays

    The POS can implement custom display handling using the Core Payments Optional Functionality.

    Query Card Functionality

    This function can be used by the POS display the app selection screen on the PIN pad to obtain a two digit "merchant id" which can be used in subsequent purchase or refund requests.

    The primary use of this function is to allow the POS to perform actions based on the payment type selected by the customer before the payment continues, such as validating if any items exist in the basket which are prohibited for the selected payment type.

    If the POS is using this function it must follow the payment flow detailed below:

    1. POS sends QueryCard to Linkly
    2. Linkly prompts customer to select payment type
    3. Customer selects payment
    4. Linkly return selected payment to POS
    5. POS processes based on returned value
    6. POS blocks transaction and ends sale OR POS initiates transaction using Merchant Code in QueryCard response
    7. Transaction initiates automatically without additional customer input

    Query Card Request

    Perform a standard QueryCard with the following property set:

    Field Name Length (characters) Description Example
    Merchant 2 Must be '99' Identifies this sale as One Button '99'
    App 2 Must be '02' to indicate a

    Query Card Response

    Field Name Length (characters) Description Example
    Merchant 2 Must be '99' Identifies this sale as One Button '99'
    Success 1 Indicates if the transaction was successful '1' = Success '0' = Failed
    Response Code 2 Response code indicating sale status '00' = Approved 'X0' = No response
    Response Text 20 Response message associated with the response code 'TRANSACTION APPROVED'
    [Bin Number] 2 2-digit Merchant identifier of payment method selected '89' = Zip '66' = Alipay '65' = Afterpay

    POS Barcode Scanning

    This function allows the POS to scan a barcode instead of the PIN pad. The POS will receive a DisplayEvent and must answer with a SendKey; populating the DataEntry field this will be the Barcode for the sale. POS must set the PCM PAD tag's first byte to '1' to indicate it can support this functionality and wants to use it for the transactions.

    Transaction Request

    Perform a sale with the following Purchase Analysis Data Tag:

    Tag Name Tag Value Description Example
    PCM Flag array of functionality supported by POS POS Capabilities Matrix. First byte = POS can scan Barcode PCM0011

    This will cause the EFT-Client to send a DisplayEvent to the POS with the following properties:

    Display Event

    Field Name Length (characters) Description Example
    NumberOfLines 2 Number of lines of text '02' – two lines
    LineLength 2 Length of each line of text '20' line is 20 char long
    DisplayText 40 Text to display 'SCAN BARCODE'
    Cancel Key Flag 1 Indicates whether the CANCEL key can be pressed '0' = Disabled '1' = Enabled
    InputData Field Key 1 See 'Custom Displays' Section '7'
    OK Key Flag 1 Indicates whether the OK key can be pressed '0' = Disabled '1' = Enabled

    The POS must reply to the above display event with a SendKey Request as detailed below:

    Send Key Request

    Field Name Length (characters) Description Example
    KeyPressed 1 Indicated which key is to be pressed '0' for the CANCEL key '1' for the YES key '2' for the NO key '3' for the AUTH key '0' = CANCEL
    InputData 60 Entry data collected by POS (the barcode) 209849083

    Purchase online, refund in-store

    When completing a refund in-store for an online purchase: * The REF pad tag indicates the unique identifier returned from the online purchase * The RFN pad tag does not need to be set * The Merchant field indicates the payment provider to perform the refund

    Example One Button refund request object

    {
        "Request": 
        {
            "Merchant": "70",
            "TxnType": "R",
            "AmtPurchase": 100,     
            "TxnRef": "1234567890",
            "CurrencyCode": "AUD",      
            "CutReceipt": "0",
            "ReceiptAutoPrint": "0",
            "Application": "02",
            "PurchaseAnalysisData":
            {
                "REF": "0b072c9f-7e96-4de3-a367-d7da6231a919",
                "OPR": "00766|test",
                "AMT": "0042000",
                "PCM": "0000"
            }
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Refund

    To call the One Button refund request, make a Core Payments refund request with Application "02", Merchant, and REF pad tag set.

    Third Party Merchant REF
    Klarna 70 Set to Order Id returned from Klarna API

    Refund Response

    The refund response is in the format of the transaction response object, see the Transaction section for a detailed breakdown.

    The CardName and Merchant properties in the response will indicate the payment type used for the refund.

    AppHub Payment specific details:

    For response codes related to One button transactions please see the response code section.

    ZipMoney:

    Receipts:

    Below is a Zipmoney Purchase Receipt

    img

    Below is a ZipMoney Refund Receipt

    img

    Field Mapping:

    References:

    Zip Transaction Receipt

    This Reference is generated by ZipMoney and sent to Linkly after a transaction request. Linkly will send this field in the 'REF' PAD Tag. This field is also printed on the receipt under the heading 'ZipMoney Reference:'

    Merchant Transaction Reference

    This reference is the POS transaction Reference passed to ZipMoney via Linkly. The POS generates this field and passes it in a Transaction Request in the 'TxnRef' field. This field is returned to the POS in a TransactionResponse in the 'TxnRef' field.

    AfterPay:

    Receipts:

    Below is an Afterpay purchase Receipt

    img

    Below is an AfterPay Refund Receipt

    img

    Field Mapping:

    References:

    merchantReference

    This reference is the POS transaction Reference passed to Afterpay via Linkly. The POS generates this field and passes it in a Transaction Request in the 'TxnRef' field. This field is returned to the POS in a TransactionResponse in the 'TxnRef' field.

    orderId

    This reference is the AfterPay reference for the sale, this is returned to the POS in the 'REF' PAD Tag. This reference is printed on the receipt under the heading 'AfterPay Order ID:'. This reference is required to perform a refund.

    refundId

    This reference is only sent for Refunds; it is the AfterPay reference for the refund, this is returned to the POS in the 'REF' PAD Tag. This reference is printed on the receipt under the heading 'AfterPay Refund ID:'

    AfterPay

    This extension adds to the core EFTPOS payment API that is provided to the POS by the Linkly EFT Client and allows the POS to perform the AfterPay transactions outlined in this section.

    Purchase

    This transaction can be used to perform a Puchase using AfterPay. Please Note: AfterPay does not support automatic reversals, and as such the POS must implement and initiate idempotent retires in the case that a response is not received for Puchase transactions; the Response Code to indicate this is 'X0'. The POS must pass in the total purchase amount for the sale in the 'AmtPurchase' in cents. Tag The POS will receive an AfterPay purchase number on the conclusion of the sale.

    Example purchase request object

    {
        "Request": 
        {
            "Merchant": "65",
            "Application": "02",
            "AmtPurchase": "200",
            "ReceiptAutoPrint":"0",
            "TxnType": "P",
            "TxnRef": "1234567890"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Example purchase response object

    {       
        "AmtPurchase": 200, 
        "AvailableBalance": 0,
        "BalanceReceived": false,
        "Caid": "C00004600001004",      
        "ClearedFundsBalance": 0,
        "Date": "2019-01-24T02:40:02",  
        "Merchant": "00",
        "Pan": "36536170",
        "PurchaseAnalysisData": 
        {
            "REF": "<AfterPay Order Id>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 17,
        "Success": true,
        "TxnRef": "J23AOI4KYHBQKQP8",
        "TxnType": "P"
    }
    

    To perform a sale, the POS will:

















    Refund

    This transaction can be used to perform a Refund using AfterPay. The POS must pass in the AfterPay Order Id in the 'REF' Tag. Please Note: AfterPay does not support automatic reversals, and as such the POS must implement and initiate idempotent retires in the case that a valid response is not received for Refund transactions; the Response Code to indicate this is 'X0'.

    Example refund request object

    {
        "Request": 
        {
            "Merchant": "65",
            "Application": "02",
            "AmtPurchase": "200",
            "PurchaseAnalysisData":
            {
                "REF" : "<AfterPay Order Id>"       
            },
            "ReceiptAutoPrint":"0",
            "TxnType": "R",
            "TxnRef": "123532465"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }   
    }
    

    Example refund response

    {   
        "AmtPurchase": 200,
        "AuthCode": 0,
        "AvailableBalance": 0,
        "BalanceReceived": false,
        "Caid": "C00004600001004",
        "CardName": "00",
        "ClearedFundsBalance": 0,
        "Date": "2019-01-24T02:58:02",
        "Merchant": "00",   
        "PurchaseAnalysisData": 
        {
            "REF": "27390"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 18,
        "Success": true,
        "TxnRef": "AQF5W1KL476XBO9I",
        "TxnType": "R"
    }
    

    A refund is where the amount is transferred from merchant's account to customer account:





















    Alipay

    This extension adds to the core EFTPOS payment API that is provided to the POS by the Linkly EFT Client and allows the POS to perform the Alipay transactions outlined in this section.

    Purchase

    This transaction can be used to perform a Puchase using Alipay. Please Note: Alipay does not support automatic reversals, and as such the POS must implement and initiate idempotent retires in the case that a response is not received for Puchase transactions; the Response Code to indicate this is 'X0'. The POS must pass in the total purchase amount for the sale in the 'AmtPurchase' in cents. Tag The POS will receive an Alipay purchase number on the conclusion of the sale.

    Example purchase request object

    {
        "Request": 
        {       
            "Application": "02",
            "AmtPurchase": "200",
            "Merchant": "66",
            "ReceiptAutoPrint":"0",     
            "TxnRef": "96B32M9UNZ421MEI",
            "TxnType": "P"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Example purchase response object

    {       
        "AmtPurchase": 200, 
        "AvailableBalance": 0,
        "BalanceReceived": false,
        "Caid": "C00004600001002",      
        "ClearedFundsBalance": 0,
        "Date": "2019-02-20T01:20:05",  
        "Merchant": "00",
        "Pan": "36536170",
        "PurchaseAnalysisData": 
        {
            "HRC": "SUCCESS",
            "STS": "TRADE_SUCCESS",
            "REF": "<Alipay Trade Number>",
            "RFN": "MCH00266RF1024<Alipay Retrieval Reference>RF2028<Alipay Trade Number>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 22,
        "Success": true,
        "TxnRef": "96B32M9UNZ421MEI",
        "TxnType": "P"
    }
    

    To perform a sale, the POS will:
















    Refund

    This transaction can be used to perform a Refund using Alipay. The POS must pass in the Alipay Order Id in the 'REF' Tag. Please Note: Alipay does not support automatic reversals, and as such the POS must implement and initiate idempotent retires in the case that a valid response is not received for Refund transactions; the Response Code to indicate this is 'X0'.

    Example refund request object

    {
        "Request": 
        {       
            "AmtPurchase": "200",
            "Application": "02",        
            "Merchant": "65",
            "PurchaseAnalysisData":
            {
                "REF" : "<Alipay Trade Number>"     
            },
            "ReceiptAutoPrint":"0",     
            "TxnRef": "VHWIAT4081T4DBR5",
            "TxnType": "R"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }   
    }
    

    Example refund response

    {   
        "AmtPurchase": 200,
        "AuthCode": 0,
        "AvailableBalance": 0,
        "BalanceReceived": false,
        "Caid": "C00004600001002",
        "CardName": "00",
        "ClearedFundsBalance": 0,
        "Date": "2019-02-20T01:38:02",
        "Merchant": "66",   
        "PurchaseAnalysisData": 
        {
            "HRC": "SUCCESS",
            "REF": "<Alipay Trade Number>",
            "RFN": "MCH00266RF1024<Alipay Retrieval Reference>RF2028<Alipay Trade Number>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 28,
        "Success": true,
        "TxnRef": "VHWIAT4081T4DBR5",
        "TxnType": "R"
    }
    

    A refund is where the amount is transferred from merchant's account to customer account:



















    Epay Wallet

    This extension adds to the core EFTPOS payment API that is provided to the POS by the Linkly EFT Client and allows the POS to perform the EPay transactions outlined in this section.

    Purchase

    This transaction can be used to purchase using a EpayWallet payment. Please see the purchase section of Alipay for alipay purchases - WeChat <!--No We chat so blah blAH add request for wechat-->

    Example wechat purchase request object

    {
        "Request": 
        {       
            "Application": "02",
            "AmtPurchase": "200",
            "Merchant": "69",
            "ReceiptAutoPrint":"0",     
            "TxnRef": "96B32M9UNZ421MEI",
            "TxnType": "P"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Example wechat purchase response object

    {       
        "AmtPurchase": 200, 
        "Caid": "C00004600001002",      
        "ClearedFundsBalance": 0,
        "Date": "2019-02-20T01:20:05",  
        "Merchant": "00",
        "Pan": "36536170",
      "OPR": "<Operator ID>",
        "PurchaseAnalysisData": 
        {
            "HRC": "<Wechat Response Code>",
            "REF": "<WeChat Purchase Reference Number>",
            "RFN": "<Refund Code>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 22,
        "Success": true,
        "TxnRef": "96B32M9UNZ421MEI",
        "TxnType": "P"
    }
    

    To perform a sale, the POS will:





















    Refund

    This transaction can be used to refund using a EpayWallet payment. Please see the refund section of Alipay for alipay refunds - WeChat <!--No We chat so blah blAH add request for wechat-->

    Example wechat refund request object

    {
        "Request": 
        {       
            "Application": "02",
            "AmtPurchase": "200",
            "Merchant": "69",
            "ReceiptAutoPrint":"0",     
            "TxnRef": "96B32M9UNZ421MEI",
            "TxnType": "R",
        "RFN": "<Refund Code>",
        "OPR": "<Operator ID>"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Example wechat refund response object

    {       
        "AmtPurchase": 200, 
        "Caid": "C00004600001002",      
        "ClearedFundsBalance": 0,
        "Date": "2019-02-20T01:20:05",  
        "Merchant": "00",
        "Pan": "36536170",
        "PurchaseAnalysisData": 
        {
            "HRC": "<Wechat Response Code>",
            "REF": "<WeChat Purchase Reference Number>",
            "RFN": "<Refund Code>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 22,
        "Success": true,
        "TxnRef": "96B32M9UNZ421MEI",
        "TxnType": "R"
    }
    

    A refund is where the amount is transferred from merchant's account to customer account:

















    Humm

    This extension adds to the core EFTPOS payment API that is provided to the POS by the Linkly EFT Client and allows the POS to perform the Humm transactions outlined in this section.

    Purchase

    This method can be used to initiate an Humm transaction. The POS must pass in the total purchase amount for the sale in the 'AmtPurchase' in cents. Tag The POS will receive an Humm purchase number on the conclusion of the sale.

    Example purchase request object

    {
        "Request": 
        {
            "Merchant": "67",
            "Application": "02",
            "AmtPurchase": "2000",
            "ReceiptAutoPrint":"0",
            "TxnType": "P",
            "TxnRef": "1234567890"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Example purchase response object

    {       
        "AmtPurchase": 2000,    
        "AvailableBalance": 0,
        "BalanceReceived": false,
        "Caid": "C00004600003001",      
        "ClearedFundsBalance": 0,
        "Date": "2019-01-11T04:17:06",  
        "Merchant": "00",
        "Pan": "956850",
        "PurchaseAnalysisData": 
        {
            "HRC": "SPRA01", 
            "REF": "<Humm Purchase Number>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 32,
        "Success": true,
        "TxnRef": "HR6RMVYUKZUZQ9S5",
        "TxnType": "P"
    }
    

    To perform a sale, the POS will:

















    Refund

    This transaction can be used to perform a Refund using Humm. The POS must pass in the Humm Purchase Number in the 'REF' Tag

    Example refund request object

    {
        "Request": 
        {
            "Merchant": "67",
            "Application": "02",
            "AmtPurchase": "2000",
            "PurchaseAnalysisData":
            {
                "REF" : "<Humm Purchase Number>"        
            },
            "ReceiptAutoPrint":"0",
            "TxnType": "R",
            "TxnRef": "1234567890"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }   
    }
    

    Example refund response

    {   
        "AmtPurchase": 2000,
        "AuthCode": 0,
        "AvailableBalance": 0,
        "BalanceReceived": false,
        "Caid": "C00004600003001",
        "CardName": "00",
        "ClearedFundsBalance": 0,
        "Date": "2019-01-11T04:27:03",
        "Merchant": "00",   
        "PurchaseAnalysisData": 
        {
            "HRC": "SPSA01"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 33,
        "Success": true,
        "TxnRef": "SR1GWD6OBEJV9E8Y",
        "TxnType": "R"
    }
    

    A refund is where the amount is transferred from merchant's account to customer account:





















    Invite

    This Method can be used to perform an Humm Invite The POS must pass in the customer phone number in the 'PHN' Tag

    Example invite request object

    {
        "Request": 
        {
            "Merchant": "67",
            "Application": "02"
            "AmtPurchase": "2000",
            "PurchaseAnalysisData":
            {
                "PHN" : "0401222333"
            },
            "ReceiptAutoPrint":"0",
            "TxnType": "K",
            "TxnRef": "1234567890"      
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        },  
    }
    

    An invite request :

    Klarna

    Introduction

    Klarna is a large Swedish bank that provides international financial services. They eliminate financial risks related to consumer credit by providing in-store credit checks and handling of customer payments.

    The Linkly Klarna extension enables the POS to perform Klarna transactions outlined in this section.

    Start Developing

    Cloud Setup

    Methods

    Once a purchase transaction request is made, the Klarna Cloud Extension will initiate a Klarna payment session, providing a QRCode for the customer to scan. Alternatively, the customer can choose to enter their phone number by clicking the button on the pinpad to receive the Payment Session link via SMS. After the customer has confirmed the payment the approved transaction will be sent back to the POS. The RFN PAD tag will contain the order id and should be stored for any future refunds.

    To integrate Klarna, it is recommended that all transactions go through the One Button API via the '99' Merchant number. Regardless, this integration must meet the minimum Core Payments requirements.

    Purchase

    This transaction can be used to perform a Purchase (QR code / SMS) using Klarna.
    Note: QR code only works on compatible terminals. Depending on registry settings and PAD fields a direct SMS purchase can be performed instead of a QR code purchase.
    Note: Selecting the SMS option (on the pinpad) at the QR code display will cancel the QR code transaction and fall back to an SMS transaction, prompting the customer to enter their phone number.
    Note: This transaction can be cancelled while the QR Code is displayed (using the Cancel button on the POS dialog), but only before the customer completes the purchase.

    Example Klarna purchase request object

    {
        "Request": 
        {       
            "Application": "02",
            "AmtPurchase": "200",
            "Merchant": "70",
            "ReceiptAutoPrint":"0",     
            "TxnRef": "96B32M9UNZ421MEI",
            "TxnType": "P",
            "CountryCode": "AU",
            "PurchaseAnalysisData":
            {
                "OPR": "00766|test",
                "AMT": "0042000",
                "PCM": "0000"
            },
            "Basket": 
            {  
                "id": "t39kq18134553",  
                "amt": 2145,  
                "tax": 200,  
                "dis": 50,  
                "sur": 0,  
                "items": [{  
                        "id": "t39kq002",  
                        "sku": "k24086723",  
                        "qty": 2,  
                        "amt": 2145,  
                        "tax": 200,  
                        "dis": 50,  
                        "name": "XData USB Drive"  
                }]  
            } 
      },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Example Klarna purchase response object

    {       
        "AmtPurchase": 200, 
        "Caid": "C00004600001002",      
        "ClearedFundsBalance": 0,
        "Date": "2019-02-20T01:20:05",  
        "Merchant": "00",
        "Pan": "36536170",
      "OPR": "<Operator ID>",
        "CountryCode": "AU",
        "PurchaseAnalysisData": 
        {
            "HRC": "<Klarna Response Code>",
            "REF": "<Klarna Purchase Reference Number>",
            "RFN": "<Refund Code>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 22,
        "Success": true,
        "TxnRef": "96B32M9UNZ421MEI",
        "TxnType": "P"
    }
    

    To perform a sale, the POS will:





















    Refund

    This transaction can be used to perform a full or partial Refund using Klarna.
    Please Note: Klarna does not support the cancellation (or reversal) of refunds

    Example Klarna refund request object

    {
        "Request": 
        {       
            "Application": "02",
            "AmtPurchase": "200",
            "Merchant": "70",
            "ReceiptAutoPrint":"0",     
            "TxnRef": "96B32M9UNZ421MEI",
            "TxnType": "R",
            "CountryCode": "AU",
            "PurchaseAnalysisData":
            {
                RFN": "<Refund Code>",
                "OPR": "00766|test",
                "AMT": "0042000",
                "PCM": "0000",
            },
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Example Klarna refund response object

    {       
        "AmtPurchase": 200, 
        "Caid": "C00004600001002",      
        "ClearedFundsBalance": 0,
        "Date": "2019-02-20T01:20:05",  
        "Merchant": "00",
        "Pan": "36536170",
        "PurchaseAnalysisData": 
        {
            "HRC": "<KLarna Response Code>",
            "REF": "<Klarna Purchase Reference Number>",
            "RFN": "<Refund Code>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 22,
        "Success": true,
        "TxnRef": "96B32M9UNZ421MEI",
        "TxnType": "R"
    }
    

    A refund is where the amount is transferred from merchant's account to customer account:

















    ZipMoney

    This extension adds to the core EFTPOS payment API that is provided to the POS by the Linkly EFT Client and allows the POS to perform the ZipMoney transactions outlined in this section.

    Purchase

    This method can be used to initiate a ZipMoney transaction. The POS must pass in the total purchase amount for the sale in the 'AmtPurchase' in cents. Tag The POS will receive a ZipMoney purchase number on the conclusion of the sale.

    Example purchase request object

    {
        "Request": 
        {
            "Merchant": "89",
            "Application": "02",
            "AmtPurchase": "1000",
            "ReceiptAutoPrint":"0",
            "TxnType": "P",
            "TxnRef": "1234567890"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }
    }
    

    Example purchase response object

    {       
        "AmtPurchase": 1000,    
        "AvailableBalance": 0,
        "BalanceReceived": false,
        "Caid": "C00004600001002",      
        "ClearedFundsBalance": 0,
        "Date": "2019-02-11T04:23:06",  
        "Merchant": "00",
        "Pan": "956850",
        "PurchaseAnalysisData": 
        {
            "HRC": "201", 
            "REF": "<ZipMoney Purchase Number>",
            "RFN": "<ZipMoney Purchase Number>"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 32,
        "Success": true,
        "TxnRef": "FQA5Q6LCW3U3EJGD",
        "TxnType": "P"
    }
    

    To perform a sale, the POS will:

















    Refund

    This transaction can be used to perform a Refund using ZipMoney. The POS must pass in the ZipMoney Purchase Number in the 'REF' Tag

    Example refund request object

    {
        "Request": 
        {
            "Merchant": "89",
            "Application": "02",
            "AmtPurchase": "1000",
            "PurchaseAnalysisData":
            {
                "REF" : "<ZipMoney Purchase Number>"        
            },
            "ReceiptAutoPrint":"0",
            "TxnType": "R",
            "TxnRef": "1234567890"
        },
        "Notification":
        {
            "Uri": "https://myPos.com.au/{{sessionid}}/{{type}}",
            "AuthorizationHeader": "Bearer <<token>>"
        }   
    }
    

    Example refund response

    {   
        "AmtPurchase": 1000,
        "AuthCode": 0,
        "AvailableBalance": 0,
        "BalanceReceived": false,
        "Caid": "C00004600001002",
        "CardName": "00",
        "ClearedFundsBalance": 0,
        "Date": "2019-02-11T04:25:03",
        "Merchant": "00",   
        "PurchaseAnalysisData": 
        {
            "HRC": "204"
        },
        "ResponseCode": "00",
        "ResponseText": "TRANSACTION APPROVED", 
        "Stan": 33,
        "Success": true,
        "TxnRef": "8V0LL1YRMM8PNN6P",
        "TxnType": "R"
    }
    

    A refund is where the amount is transferred from merchant's account to customer account:





















    Appendix

    Appendix A - Merchant Codes

    Below are the Merchant codes that can be entered into a Merchant field, this will perform the request/method ONLY with the merchant specified, unless the merchant is '00'.
    The Default merchant is '00' which is EFTPOS, for regular sales and requests use this Merchant code.

    Note: Not all functions are supported by all merchants.

    MERCHANT IDs & TID PREFIX FOR TPP DLL's

    Merchant Code / Merchant HostId Description
    51 / WLT Wishlist
    52 / GVX Givex
    53 / BHN Blackhawk
    54 / PPL Paypal
    55 / ZOO Zoo Republic
    56 / EPY ePay (Not Used)
    57 / FDI FDI
    58 / TBM The Bored Monkey
    59 / WEX WrightEXpress
    60 / RNT Rental Payments / NAB Transact
    61 / HRS Harris Scarfe
    61 / UNP United Petroleum (Fuel Card/Shopper Docket)
    61 / FUS Fusion Loyalty
    62 / QLG Qantas Loyalty Gateway
    63 / EPY ePay Universal Protocol
    64 / INC Incomm
    65 / AFP AfterPay
    66 / ALI Alipay
    67 / ?? Humm
    70 / KLA Klarna
    ?? / ARK Arkade Loyalty
    89 / ZMY ZipMoney
    90 / TRU TruRating
    99 / SLV Slave

    Note: 61 can be used for any proprietary in-house extension that will never be deployed outside a given merchant.

    Appendix B - Response Codes

    Below are the response codes to a specific function. The codes are usually associated with a 'Response Text' that describe the result of the function performed.
    Eg. 00 for a transaction is approved and its Response Text is "APPROVED ".

    Common Response Codes

    Response Code Response Text Additional Information
    00 APPROVED Transaction / function completed successfully
    78, 79, XG SYSTEM ERROR ANZ Specific:
    Bank configuration issue
    97 ALREADY SETTLED PIN pad already has been settled
    B1 PRINTER ERROR Linkly setup to handle printing, but no printer defined
    BB / BY Client/Pinpad Busy Pinpad/client are processing
    N8 SERVER ERROR Invalid TID entered into the PIN pad
    P7 COMMS ERROR Comms issue with the PIN pad or the EFT server
    PF Pinpad Offline Pinpad is offline
    S0 MODEM ERROR (Should be CBA only) Generic Connection error - can't connect to the bank
    S7 NO EFT SERVER Linkly EFT Client is not connecting to EFT Server
    S8 NO EFT SERVER Error in the lines tab of the EFT Server
    TB TMS REQUIRED PIN pad needs to logon to TMS
    TF INIT REQUIRED PIN pad needs to be logged on
    TI Operator Timeout Input timeout
    TM Operator Cancelled Operator cancelled sale
    TX Unable to Process Reversal failed to process
    X0 NO RESPONSE Bank not responding to the terminal
    X0J No Response Message timeout
    X2 System Error Internal Error
    XG Txn Not Supported Txntype is not supported
    XT CONFIG REQUIRED PIN pad not configured with TID/MID
    Z0 Modem Error No connection from eftsrv
    Z5 Power Fail The PINpad has lost power/recovered from a powerFail
    ZB PINPAD BUSY ANZ Specific:
    PIN pad is not ready to accept transaction

    Developer-Specific Response Codes

    Response Code Response Text Additional Information
    00 APPROVED
    08 Approved
    A1 Recursive Call ActiveX busy
    A4 Invalid Merchant Merchant does not exist
    A7 Internal Buffer ActiveX message smaller than expected
    B2 Unsupported Operation
    B3 Client Offline Client not running / another program using client
    B4 Internal Buffer ActiveX message larger than expected
    B5 Invalid Amount POS sent wrong amount
    B6 Invalid Dialog
    B7 Invalid TxnType
    B8 Invalid TxnRef
    BY PINpad Busy
    D0 Invalid AuthCode POS sent wrong AuthCode
    E2 No Previous Txn
    TG Display Error POS display error
    TH Printer Error POS Printer Error
    Z0 Modem Error
    Z5 Power Fail

    AppHub Response Codes

    Response Code Response Text Description
    99 General Decline Unexpected Error
    97 Auth Error Linkly Auth Error – Token is invalid
    H0 Config Required Lane Info/Third party host credentials are missing
    H1 POS Format Error POS has sent a wrong/missing field in the request
    HA Invalid Amount The Amount does not match Third party requirements
    HB Insufficient Funds The customer account does not have sufficient funds for the transaction
    HC Host Format Error The message is incorrect to the third party
    HD Txn Cancelled The txn has been cancelled
    HE Bad Read The card data/barcode provided is invalid
    HG Host Auth Error Authentication error from the third party
    HH Txn Not Found The txn reference does not exist on the third party system
    HI Expired payment The barcode/qrcode/card has expired and cannot be processed
    HL Host Internal Error Internal error on the third party system
    HM Activation Error Third party activation error
    HN Account In Use The account/payment authenticator is already in use
    HQ Account Funds Error There is a funds error with the specified account
    HR Already processed The specific sale is already processed
    HS Account Error There is an issue with the customer account

    Appendix C - Purchase Analysis Data

    {
        ...,
        "PurchaseAnalysisData": {
                "<TagName>": "<tagValue>",
                "PAT": "1"
            }
    }
    
    

    The purchase analysis data field allows the POS to send custom tag data to the pinpad.
    It is also possible for the pinpad to return data to the POS in the field for certain messages.
    The format for both send and receive of this data is the same. The value of each tag is dependent upon the pinpad application.

    Only use this field if instructed by Linkly.

    Byte Position Field Length Description
    THE FOLLOWING FIELDS ARE REPEATED FOR EACH TAG.
    0 Tag Name 3 The name of the tag as defined by the pinpad
    2 Tag Data Length 3 The length of the tag data to follow, not including the tag name and data length fields. ASCII and padded with leading zeros.
    5 Tag Data X The tag data as defined by the pinpad

    Example 1:
    Setting the property to "XXX006ABCDEF" would mean the pinpad receives a tag called 'XXX' with a length of 6 and the data 'ABCDEF'

    Example 2:
    Setting the property to "XXX001aYYY003ABCZZZ00245" the pinpad receives:

    Silent Card Not Supported In Transaction

    Limit Account Selection

    Operator Display Prompts

    Field 48 Data

    Myer Specific

    Tip value passed from POS

    Amount tag

    SKU tag

    Unique Card Identifier

    Available Balance

    Cleared Funds Balance

    Operator Reference

    Unique Identifer

    POS Name

    POS Version

    POS Vendor ID

    POS Capabilities Matrix

    Purchase REF

    Host Response Code

    Host Response Text

    Appendix D - Application Codes

    Code Application
    '00' EFTPOS
    '01' AGENCY
    '02' Linkly Configurable Application
    '03' Gift Card
    '04' Fuel
    '05' Medicare
    '06' Amex
    '07' Cheque Auth

    Appendix E - TxnType

    Description:
    This property should be set to indicate the type of transaction to be performed when calling DoTransaction or DoSettlement.

    Values Application
    B Balance Enquiry.
    P Purchase, Purchase & Cash
    R Refund
    C Cash Only
    D Deposit
    The deposit amount is placed in AmtPurchase (excluding STG Agency terminal)
    St George Agency terminal note:
    AmtPurchase contains the cheque amount
    AmtCash contains the cash amount to deposit
    TotalPurchaseCount contains the total number of cheques to deposit.
    L Completion
    M Auto-Completion
    The following properties must be set prior to this call:
    - rrn (as returned in original request)
    - auth code (as returned in original request)
    - amtpurchase.
    - txnref
    - PANSource
    - track2 (as returned in original request)
    - AccountType(as returned in original request)
    V Voucher Entry
    The following properties must be set prior to this call:
    AccountType ('0' = Savings, '1' = Cheque, '2' = Credit, '3' = Account 1, '4' = Account 2, '5' = Account 3, '6' = Account 4, '7' = Account 5)
    - Date (DDMMYY)
    - Time (HHMMSS)
    - rrn (as returned in original request)
    - auth code (as returned in original request)
    - amtpurchase.
    - txnref
    - PANSource = 'K'
    - pan (contents of the PAN)
    - dateExpiry (MMYY)
    - CsdReservedString3 (Card Sequence Number. Normally 2 digits)
    - DataField (The original transaction type. 'P', 'C', 'R', 'D' )
    T Tip-Adjustment
    The following properties must be set prior to this call:
    - rrn (as returned in original request)
    - auth code (as returned in original request)
    - amtpurchase.
    - txnref
    - PANSource
    - track2 (as returned in original request)
    - dateExpiry (if manually keyed)
    - Pan (if manually keyed)
    - AccountType (as returned in original request)
    W Withdrawal
    The withdrawal amount is to be set in the amtpurchase property.
    F Funds Transfer
    The amount to transfer is to be placed in the amtpurchase property
    O Order Request
    An order request will ask the bank to send something to the customer (eg statement, cheque book, etc)
    H Mini Transaction History
    Retrieve recent transaction details based upon the customer's card details
    X Get and Authorise a PIN
    Ask the customer for their PIN, and authorise it with the bank
    K Enhanced PIN command
    This will perform an enhanced PIN command as defined by the bank PIN pad
    The following properties can be set prior to this call:
    - amtpurchase.
    - txnref
    - PANSource
    - track2 (as returned in original request)
    - dateExpiry (if manually keyed)
    - Pan (if manually keyed)
    - AccountType (as returned in original request)
    - DataField
    I Void

    Settlement Types

    Returned by TransactionEvent and SettlementEvent.
    Applies to DoTransaction and DoSettlement.
    Note: Not all TxnTypes are supported by all acquirers.

    Appendix F - Cloud Account

    Steps to request a cloud test account

    Appendix G - Virtual PIN pad

    Steps to setup a virtual PIN pad

    Appendix H - Legacy pairing

    The Linkly Cloud REST API uses token authentication. A token is an encrypted and signed string of data that represents authentication credentials that are specific to a particular PIN pad, and the POS system will need to maintain the token for each PIN pad it uses. Linkly uses the industry standard JWT tokens, and the token is added to each request as an HTTP header with the keyword Bearer. The POS does not need to know how to create the token itself, it only needs to request one from the Linkly Authentication server.

    To request a token the POS must have a valid Linkly Cloud Client username and password from Linkly, plus the PIN pad pair code. Once a valid token has been created, the POS can make API requests by including the token in the Authorisation header as outlined below.

    Legacy Token Request

    Legacy Token request

    # replace <<username>>, <<password>>, and <<paircode>> with your own
    # replace <<posName>> and <<posVersion>> with the name and version of your POS
    # replace <<posId>> with a unique uuid that identifies your POS
    curl "https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos" \
      -X POST \
      -H 'Content-Type: application/json' \
      -H 'Accept: application/json' \
      -d '{
            "username": "<<username>>",
            "password": "<<password>>",
            "paircode": "<<paircode>>",
            "posName": "<<posName>>",
            "posVersion": "<<posVersion>>",
            "posId": "<<posId>>"
          }'
    
    // replace <<username>>, <<password>>, and <<paircode>> with your own
    // replace <<posName>> and <<posVersion>> with the name and version of your POS
    // replace <<posId>> with a unique uuid that identifies your POS
    var requestContent = new
    {
        Username = "<<username>>",
        Password = "<<password>>",
        PairCode = "<<paircode>>",
        PosName = "<<posName>>",
        PosVersion = "<<posVersion>>",
        PosId = "<<posId>>"
    };
    
    var request = new HttpRequestMessage(HttpMethod.Post, "https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos")
    {
        Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestContent), System.Text.Encoding.UTF8, "application/json")
    };
    
    var httpClient = new HttpClient(); // Note: in production don't create multiple HttpClient instances. Share one single instance.
    HttpResponseMessage httpResponse = await httpClient.SendAsync(request);
    string responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    import requests; # http://python-requests.org
    
    # replace <<username>>, <<password>>, and <<paircode>> with your own
    # replace <<posName>> and <<posVersion>> with the name and version of your POS
    # replace <<posId>> with a unique uuid that identifies your POS
    request_payload = {
        'username': '<<username>>',
        'password': '<<password>>',
        'pairCode': '<<paircode>>',
        'posName': '<<posName>>',
        'posVersion': '<<posVersion>>',
        'posId': '<<posId>>'
    }
    response = requests.post('https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos', json=request_payload)
    response_payload = response.json()
    

    URI Path

    Production:

    POST https://auth.cloud.pceftpos.com/v1/tokens/cloudpos

    Development Sandbox environment:

    POST https://auth.sandbox.cloud.pceftpos.com/v1/tokens/cloudpos

    Headers

    Parameter Value
    Content-Type application/json
    Accept application/json

    Request Body

    Example token request object

    {
        "username": "123456789",
        "password": "QWERTY",
        "pairCode": "09876",
        "posName": "Test POS",
        "posVersion": "12.6.80.17",
        "posId": "3e7f5001-58a3-43fa-9129-6e84a7b4f2a0"
    }
    
    Field KeyName Required Description
    Username Yes The Linkly Cloud username
    Password Yes The Linkly Cloud password
    PairCode Yes The PIN pad pair code returning from the pairing process
    PosName Yes The name of the POS requesting the token
    PosVersion Yes The version of the POS requesting the token
    PosId Yes A unique UUID that identifies the POS

    Status Codes

    Code Description Required action
    200 Authorisation was successful. The response object will contain the auth token. Store and maintain the token based on the expirySeconds property.
    401 The username, password, or 'pair code' was invalid. Re-check the Cloud username, try resetting the Cloud password, or try re-pairing the PIN pad to get a new pair code.
    400 Invalid request. Correct the request and try again.
    408 Request Timeout. This should be rare: a transient error has occurred, possibly due to server overloading. Wait a few seconds and attempt the request again. If the problem persists, contact Linkly Support.
    500-599 A server error has occurred. Wait a few seconds and attempt the request again. If the problem persists, contact Linkly Support.

    Legacy Auth Response

    Example token response object

    {
        "token":"x2MUks9vdreTp8aHjfcULkQxURurcRCb",
        "expirySeconds":86400 
    }
    
    Field KeyName Description
    token The token to user for authentication.
    expirySeconds The number of seconds until the token expires.

    Using the token

    The Bearer token is added to each request as an HTTP header with the keyword Bearer as shown below:

    Authorization: Bearer <token goes here>

    When a token is received from the Linkly Authentication service it is the responsibility of the POS to securely store and manage the lifetime of that token and request a new one when the old token has expired.

    The expirySeconds is returned with each token response. This value indicates the number of seconds until the token expires. The POS can use this value to calculate and record the local expiry date and time.

    We recommend requesting a new token if it is due to expire within a few minutes of the request.

    The POS can request tokens as often as required, however if the POS requests a new token for each transaction or each request this will slow down transaction times. Be aware that requesting a new token does not currently cause existing valid tokens to be revoked, but this may change in future without warning.

    During an async transaction, be aware that if the token expires mid-transaction it will need to be renewed if the POS needs to send a sendkey request to the PIN pad.

    C# example: checks to see if the token has expired

    class TokenResponse
    {
        public string Token { get; set; }
        public double ExpiryMinutes {
            get
            {
                return (ExpiryDateTime - DateTime.UtcNow).TotalMinutes;
            }
            set
            {
                ExpiryDateTime = DateTime.UtcNow.AddMinutes(value);
            }
        }
        public DateTime ExpiryDateTime { get; set; } = DateTime.UtcNow;
    }
    
    TokenResponse token = null;
    
    private async Task<T> PostRequestAsync<T>(Uri baseUri, Guid sessionId, string type, EFTRequest request, bool async)
    {
        var httpClient = GetHttpClient(); // Get a pre-constucted HttpClient from some repository, factory, or static instance
        if (token == null || token.ExpiryDateTime < DateTime.UtcNow.AddSeconds(10)) // notice 10 second offset
        {
            token = await GetTokenAsync(appSettings.PinpadUsername, appSettings.PinpadPassword, appSettings.PinpadPairCode);
    
            if (token == null || string.IsNullOrWhiteSpace(token.Token))
            {
                throw new Exception("Failed to get valid token");
            }
        }
    
        var uri = new Uri(baseUri, $"sessions/{sessionId}/{type}?async={async.ToString().ToLower()}");
    
        var request = new HttpRequestMessage() 
        {
            RequestUri = new Uri("http://www.someURI.com"),
            Method = HttpMethod.Post,
        };
        request.Headers.Accept.Add(new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token.Token);
        HttpContent content = new StringContent(JsonConvert.SerializeObject(request), UTF8Encoding.UTF8, "application/json");
    
        var response = await httpClient.SendAsync(request);
    
        if (response.IsSuccessStatusCode)
        {
            if (async)
            {
                return default(T); // nothing to return, now it's time to wait for the postbacks
            }
            return JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
        }
        else             
        {
            switch (response.StatusCode)
            {
                case System.Net.HttpStatusCode.Unauthorized:
                    throw new UnauthorizedAccessException("Looks like the username, password or pair code is no longer valid, or your account has been disabled. Try re-pairing the PIN pad or resetting the password.");
                case System.Net.HttpStatusCode.NotFound:
                    throw new Exception("Ooops, this shouldn't happen.  Check that your base URI and type are correct.");
                case System.Net.HttpStatusCode.BadRequest:
                    throw new Exception("That request wasn't valid! Inspect the response message to see what's wrong.");
                default:
                    throw new Exception("Server error, timeout, PIN pad error, etc. Call GET /sessions/{id}/transaction to see the status of this transaction or try again later.");
            }
        }
    }
    

    Document Version

    Version Date Revisions
    1.0.3 18 August 2022 - Updating POS Support email to [email protected]
    1.0.2 23 June 2022 - Removing Deprecated TxnType 'G' (MOTO); Use PanSource to perform MOTO transactions
    1.0.1 31 May 2022 - Updating jquery version
    - moving Document Version section to end of document
    1.0.0 16 May 2022 - Removed pre-authorisation and bar tab