This document walks through a complete Sale transaction with real captured hex data from a live GHL terminal.
| Field | Value | ASCII | Hex bytes |
|---|---|---|---|
| Command (3) | Sale | 020 |
30 32 30 |
| Amount (12) | RM 0.01 = 1 cent | 000000000001 |
30 30 30 30 30 30 30 30 30 30 30 31 |
| Invoice (6) | 1 | 000001 |
30 30 30 30 30 31 |
| Cashier (4) | 99, right-justified | ` 99 | 20 20 39 39` |
ASCII: 020000000000001000001 99
Hex: 30 32 30 30 30 30 30 30 30 30 30 30 30 30 31 30 30 30 30 30 31 20 20 39 39
Split into 8-byte blocks:
Block 1: 30 32 30 30 30 30 30 30
Block 2: 30 30 30 30 30 31 30 30
Block 3: 30 30 30 31 20 20 39 39
Block 4: FF FF FF FF FF FF FF FF (padding -- only 1 byte was needed but pad to 8)
XOR result: 09 CD CF CF CE DF DE C6
02 30 32 30 30 30 30 30 30 30 30 30 30 30 30 31
30 30 30 30 30 31 20 20 39 39 09 CD CF CF CE DF
DE C6 03
Breakdown:
02 = STX
30 32 30 = "020" (Sale command)
30 30 30 30 30 30 30 30 30 30 30 31 = "000000000001" (RM 0.01)
30 30 30 30 30 31 = "000001" (Invoice)
20 20 39 39 = " 99" (Cashier)
09 CD CF CF CE DF DE C6 = Checksum (8 bytes)
03 = ETX
After the TX packet is sent over the serial port:
This entire process typically takes 5-15 seconds for a contactless tap.
02 30 32 31 30 30 34 30 30 30 31 32 33 34 58 58
58 58 58 58 39 38 37 36 30 30 30 30 33 32 30 32
30 38 31 34 32 32 30 33 20 20 30 30 30 30 30 30
30 30 30 30 30 31 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 35 33 30 30 30 30 33 30 20 20
39 39 20 20 20 20 20 20 20 20 4D 59 44 45 42 49
54 92 F0 EA 91 9B E5 EB FF 03
Strip STX (first byte) and Checksum+ETX (last 9 bytes) to get the payload:
Payload (96 bytes):
30 32 31 30 30 34 30 30 30 31 32 33 34 58 58 58
58 58 58 39 38 37 36 30 30 30 30 33 32 30 32 30
38 31 34 32 32 30 33 20 20 30 30 30 30 30 30 30
30 30 30 30 31 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 35 33 30 30 30 30 33 30 20 20 39
39 20 20 20 20 20 20 20 20 4D 59 44 45 42 49 54
| Offset | Hex | ASCII | Field | Interpretation |
|---|---|---|---|---|
| 0-2 | 30 32 31 |
021 |
Response code | Sale response |
| 3-4 | 30 30 |
00 |
Error code | APPROVED |
| 5-26 | 34 30... |
40001234XXXXXX9876... |
Card number | Masked debit card |
| 27-30 | 33 32 30 32 |
3202 |
Card expiry | February 2032 |
| 31-32 | 30 38 |
08 |
Card type | MyDebit |
| 33-40 | 31 34 32 32 30 33 20 20 |
142203 |
Auth code | Bank authorization code |
| 41-52 | 30 30...30 31 |
000000000001 |
Gross amount | RM 0.01 |
| 53-64 | 30 30...30 30 |
000000000000 |
Net amount | RM 0.00 |
| 65-70 | 30 30 30 30 35 33 |
000053 |
Trace (STAN) | System trace number |
| 71-76 | 30 30 30 30 33 30 |
000030 |
Invoice | Invoice number |
| 77-80 | 20 20 39 39 |
` 99` | Cashier | Cashier ID |
| 81-95 | 20...4D 59 44 45 42 49 54 |
` MYDEBIT` | Card name | Card brand string |
Note: This response is 96 bytes (older firmware), so TID, MID, and Batch Number fields are not present. With firmware v1.0.17+, the response would be 125+ bytes and include those additional fields.
Here is a second transaction that was cancelled by the user on the terminal:
Error code at offset 3-4: 43 54 = ASCII CT = Cancelled/Timeout
Offset 3-4: CT (Cancelled)
Card number: 0000000000000000000000 (all zeros -- no card was read)
Card expiry: 0000
Card type: 00 (unknown)
Auth code: (empty)
When the error code is anything other than 00, the card fields will typically be empty or zeroed out, since no card transaction actually occurred.
On a successful transaction, your POS should display/print a receipt like:
=========================================
*** APPROVED ***
=========================================
MERCHANT ID: [from response or config]
TERMINAL ID: [from response or config]
TIME: 2026-03-19 11:52:15
BATCH NO: [from response]
-----------------------------------------
STAN: 000053
INVOICE: 000030
-----------------------------------------
TRANS TYPE: SALE
CASHIER ID: 99
CARD NO: **** **** **** 9876
EXPIRY: 02/32
CARD TYPE: 08 (MYDEBIT)
AUTH CODE: 142203
-----------------------------------------
GROSS AMT: RM 0.01
NET AMT: RM 0.00
-----------------------------------------
THANK YOU!
=========================================