{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-docs/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Testing","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"testing","__idx":0},"children":["Testing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A couple of options are available to help POS developers test their Pay@Table implementation:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["CLI test harness."]}," A Java-based command-line interface test harness emulates the messaging"," ","between terminal and POS server. The software is distributed as a downloadable archive, with"," ","instructions for use included in the archive."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Development terminal."]}," Tyro can provide development terminals for up to 3 months. The"," ","terminal connects to Tyro's pre-production network and comes with a set of test cards. The"," ","development terminal processes transactions using these test cards with no actual financial"," ","effect."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"certification-and-testing-process","__idx":1},"children":["Certification and testing process"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All POS partners must pass Tyro's mandatory certification process before going into production"," ","with a Pay@Table integration. The certification process includes a testing component, which"," ","broadly involves:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Providing the completed Tyro integration form and proof-of-functionality videos for the"," ","integration, once development and internal testing has concluded."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Providing a sandbox version of the Pay@Table integration so Tyro can test it. Depending on the"," ","environment, platform and language used, the exact form this takes varies — specific"," ","instructions are provided at this stage by the Tyro Presales and Partner Support team member"," ","handling the project."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Testing the integration, with regular feedback back to the POS partner for any issues that need"," ","addressing. The Tyro Certification Criteria determines feature eligibility for certification,"," ","barring any exceptions granted."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Once certification is complete, POS vendors can go into production. Tyro suggests running a pilot"," ","program before a broader release."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"generating-and-verifying-message-authentication-codes","__idx":2},"children":["Generating and verifying Message Authentication Codes"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Pay@Table integration involves transmitting transaction requests and responses between the POS"," ","Pay@Table server and the Tyro terminal. This requires measures to ensure the validity and integrity"," ","of message contents. Tyro's Pay@Table protocol uses HMAC-SHA1 (HMAC using the SHA1 cryptographic"," ","hash function) to reasonably ensure that communication between the POS Pay@Table server and the"," ","Tyro terminal has come from the correct source and hasn't been modified in any way."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In simple terms, a Message Authentication Code (MAC) is a short piece of information used to"," ","authenticate a message."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["MAC generation uses a MAC algorithm — sometimes called a keyed cryptographic hash function — which"," ","takes two inputs, a secret key and an arbitrary-length message to be authenticated, and produces a"," ","MAC as output. The MAC value protects both the message's data integrity and its authenticity, by"," ","letting verifiers who also possess the secret key detect any changes to the message content."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The MAC is sent along with the message to the receiver, who uses the secret key to generate a MAC"," ","from the received message and compares it with the MAC that was sent. If the two match, this"," ","confirms the validity and authenticity of the message."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The MAC algorithm adopted here is ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"http://en.wikipedia.org/wiki/HMAC"},"children":["HMAC"]}," — a Hash-based Message"," ","Authentication Code, a secure MAC algorithm implemented across a wide range of programming"," ","languages, including .NET, Java and C."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Sample code for MAC generation using the SHA1 cryptographic hash function, in C# and Java:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["C# sample code:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"c#","header":{"controls":{"copy":{}}},"source":"byte[] mac = new HMACSHA1(passphrase).ComputeHash(message);\n","lang":"c#"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Java sample code (1.4+):"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"java","header":{"controls":{"copy":{}}},"source":"Mac hmac = Mac.getInstance(\"HmacSHA1\");\nSecretKeySpec secret = new SecretKeySpec(passphrase.getBytes(\"ISO-8859-1\"), \"HmacSHA1\");\nhmac.init(secret);\nbyte[] mac = hmac.doFinal(message.getBytes(\"ISO-8859-1\"));\nString macAsHex = Hex.encodeHexString(mac);\n","lang":"java"},"children":[]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["MAC verification only applies to the following requests:",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["POST requests for transaction responses (terminal to Pay@Table server)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["All request responses (GET open sales request response, GET diagnostics request) by the POS"," ","Pay@Table server to the Tyro terminal."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["MAC verification on the POS Pay@Table server doesn't apply to GET open sales and diagnostics"," ","requests sent by the Tyro terminal, since there's no message content in the HTTP request for the"," ","MAC to be calculated against — so no MAC is specified by the Tyro terminal in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["x-tyro-mac"]}," ","request header for these requests."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The POS Pay@Table server, however, must calculate the MAC against the message contained in the"," ","response being returned to the Tyro terminal, and the terminal performs MAC verification to"," ","confirm the validity of that message."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["MAC verification therefore applies to all responses returned by the POS Pay@Table server to the"," ","Tyro terminal, since there's content to compute the MAC against in these cases."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The MAC is provided to the receiving party as an HTTP header named ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["x-tyro-mac"]}," in the HTTP"," ","request or response."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The receiving party must verify the message using the received MAC (in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["x-tyro-mac"]}," header)"," ","by computing the MAC for the received message using the process above, then comparing the"," ","computed MAC with the received MAC to confirm they're identical."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If MAC verification by the POS Pay@Table server fails, the POS Pay@Table server must return an"," ","HTTP status code of 403."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An example of failed MAC verification:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Request type: POST request by the Tyro terminal, posting an approved transaction response back"," ","to the POS Pay@Table server."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Transmitted message: ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Approved transaction response message transmitted"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Passphrase (secret): ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["p@ssphr@se"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Generated and transmitted MAC: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["e15c06852f355065ef2d044b0334fa14d43bd85d"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["During transmission, the message has had its amount changed from $1.00 to $100.00."]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Received message: ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Approved transaction response message received"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Passphrase (secret): ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["p@ssphr@se"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Generated MAC: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["c6a578066f2b77c97261833bb47bebdc6b9717bf"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Comparing the received MAC (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["e15c06852f355065ef2d044b0334fa14d43bd85d"]},") with the generated MAC"," ","(",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["c6a578066f2b77c97261833bb47bebdc6b9717bf"]},") shows a mismatch, confirming that the message sent"," ","wasn't the one received — so the POS Pay@Table server returns a 403 HTTP status code to the Tyro"," ","terminal."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"table-locking","__idx":3},"children":["Table locking"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Table locking is a Pay@Table feature that lets access to tables opened on either the POS program or"," ","the Tyro terminal be locked down, so the other end can't access them while they're being accessed"," ","on one end. This means:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Tables being accessed, edited or modified on the POS program can't be pulled by the Tyro terminal"," ","through a GET open sales request — this is POS-side locking."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The sequence for this case:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A stored open sale is opened on the POS program to edit the open sale."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["POS logic renders the table open on the POS as \"unavailable\" in the database."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Attempting to pull the table with a table number that's open on the POS results in the Tyro"," ","terminal sending the GET open sales request."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The POS Pay@Table server returns an HTTP 412 error code, along with the message the POS wants"," ","displayed on the Tyro terminal screen — up to ninety characters; longer messages are truncated"," ","to the first ninety. If no message is provided, the terminal displays a default message:"," ","\"Table is unavailable at this time.\""]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Tables open and ready to be closed on the Tyro terminal can't be edited or opened on the POS"," ","program until they're released by the terminal — this is terminal-side locking."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The sequence for this case:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A stored open sale is opened on the Tyro terminal using the GET open sales request. This"," ","request needs ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["always-return-outcome"]}," set to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]},", to let the terminal participate in table"," ","locking."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The sale is successfully returned to the terminal and awaits the cardholder tapping, swiping or"," ","inserting their card to process the transaction."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["POS logic renders the table open on the terminal as \"unavailable\" in the database, so it can't"," ","be accessed on the POS until it's released by the terminal — i.e. a partial payment for the"," ","table is made, or the user releases the table on the terminal."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Any attempt to access the table on the POS while it's open on the terminal results in the POS"," ","interface displaying a message that the table is currently open on the Tyro terminal."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The POS can use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CANCELLED"]}," transaction response returned by the terminal, once the table"," ","is released, to unlock the table for access on the POS."]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Table locking controls concurrent access to tables and prevents scenarios where table details are"," ","modified while the table is already open and being paid off on the terminal."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"integrated-tipping","__idx":4},"children":["Integrated tipping"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Tyro terminals have a built-in tipping workflow that can be enabled on the terminal. When enabled,"," ","the terminal prompts the cardholder to specify a tip amount during the transaction workflow. There"," ","are two kinds of tipping on Tyro terminals:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Manual tipping"]}," — see"," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://help.tyro.com/s/article/How-does-tipping-work-on-my-EFTPOS-terminal"},"children":["How does tipping work on my EFTPOS terminal"]}," ","for more details."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Percentage tipping"]}," — see"," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://help.tyro.com/s/article/How-to-enable-percentage-tipping"},"children":["How to enable percentage tipping"]}," ","for more details."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The cardholder can choose to tip an arbitrary amount or a percentage of the transaction amount. Any"," ","approved transaction with a tip added returns the tip amount in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["tip-amount"]}," field of the"," ","approved transaction response. The POS must use that value when reporting tip amounts on receipts"," ","and in internal end-of-day POS reconciliation and tip reports."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An example of a transaction carrying both a surcharge and a tip amount:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n \"approval-code\": \"000006\",\n \"base-amount\": \"100.00\",\n \"base-currency\": \"AUD\",\n \"card-currency\": \"AUD\",\n \"card-type\": \"Visa\",\n \"elided-pan\": \"xxxxxxxxxxxx9521\",\n \"issuer-action-code\": \"00\",\n \"mid\": \"850\",\n \"operator-id\": \"6\",\n \"pan-length\": \"16\",\n \"pos-reference\": \"MUCJBZDOG3\",\n \"receipt-block\": \"\n       Pay@table test      \n      123 test street      \n      Sydney NSW 2000      \n \n       MERCHANT COPY       \n \n    Tyro Payments EFTPOS   \n \nNAB Visa Credit\nAID: A0000000031010\nCard: xxxxxxxxxxxx9521 (t)\n \nPurchase    AUD     $100.00\nTip         AUD       $5.00\nSub-Total   AUD     $105.00\nSurcharge   AUD       $0.50\n                 ----------\nTotal       AUD     $105.50\n \nAPPROVED              00\n \nTable number: 0\nTerminal ID: 437\nTransaction Ref: 460033\nAuthorisation No: 000006\n25 Jan 2021 at 04:52 PM\n \nRetain copy for your records\n \nResponse time: .94 sec\n \n\",\n \"response-message\": \"APPROVED\",\n \"result\": \"APPROVED\",\n \"rrn\": \"102516460033\",\n \"surcharge-amount\": \"0.50\",\n \"table\": \"0\",\n \"terminal-transaction-local-date-time\": \"20210125165211+1100\",\n \"tid\": \"437\",\n \"tip-amount\": \"5.00\",\n \"transaction-amount\": \"105.50\",\n \"transaction-currency\": \"AUD\",\n \"transaction-reference\": \"460033\",\n \"transaction-type\": \"purchase\",\n \"transmission-date-time\": \"20210125055211+0000\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"tyro-paytable-simulator","__idx":5},"children":["Tyro Pay@Table simulator"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A Java command-line test harness is available for POS vendors developing and testing a Pay@Table"," ","implementation. It generates the same messages a terminal in Pay@Table mode would send."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The archive includes its own instructions for use."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/assets/paytablesimulator.722e3831d13f932a7f9f7f8de4004d54a8e999483103ade2602141f5631328cb.fbf1555a.zip"},"children":["Pay@Table simulator"]}]}]},"headings":[{"value":"Testing","id":"testing","depth":1},{"value":"Certification and testing process","id":"certification-and-testing-process","depth":2},{"value":"Generating and verifying Message Authentication Codes","id":"generating-and-verifying-message-authentication-codes","depth":2},{"value":"Table locking","id":"table-locking","depth":2},{"value":"Integrated tipping","id":"integrated-tipping","depth":2},{"value":"Tyro Pay@Table simulator","id":"tyro-paytable-simulator","depth":2}],"frontmatter":{"title":"Testing","seo":{"title":"Testing"}},"lastModified":"2026-10-06T01:06:05.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/in-person-payments/pay-in-person/features/pay-at-table/testing","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}