Skip to main content

ECR Interface Protocol

1. Encrypt the data of the protocol

1.1 Get a 6-digit pair Pin Code

When the Wonder terminal enters the pair page, a 6-digit pair Pin Code(pinCode1) or the QR code generated by it will be displayed. The client device can obtain this string by scanning a code or manually entering it

Example:
const pinCode1 = '260880';

1.2 Encrypt the data of the protocol with AES256


<!DOCTYPE html>
<html lang="zh-CN">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>浏览器端AES加解密演示</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f7fa;
color: #333;
line-height: 1.6;
padding: 20px;
}

.container {
max-width: 1200px;
margin: 0 auto;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}

.header {
background-color: #4a90e2;
color: white;
padding: 20px;
text-align: center;
}

.header h1 {
font-size: 24px;
font-weight: 500;
}

.content {
padding: 30px;
}

.section {
margin-bottom: 30px;
padding: 20px;
border-radius: 8px;
border: 1px solid #e1e8ed;
background-color: #fafbfc;
}

.section-title {
font-size: 18px;
font-weight: 500;
margin-bottom: 15px;
color: #4a90e2;
border-bottom: 1px solid #e1e8ed;
padding-bottom: 8px;
}

.form-group {
margin-bottom: 15px;
}

.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: #555;
}

.form-group input,
.form-group textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
font-family: inherit;
}

.form-group textarea {
resize: vertical;
min-height: 100px;
}

.btn {
background-color: #4a90e2;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
margin-right: 10px;
margin-bottom: 10px;
transition: background-color 0.3s;
}

.btn:hover {
background-color: #357abd;
}

.btn-secondary {
background-color: #6c757d;
}

.btn-secondary:hover {
background-color: #5a6268;
}

.result {
margin-top: 20px;
padding: 15px;
border-radius: 4px;
background-color: #e9ecef;
font-family: 'Courier New', Courier, monospace;
font-size: 14px;
word-break: break-all;
}

.result.success {
background-color: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}

.result.error {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}

.test-results {
margin-top: 20px;
}

.test-item {
margin-bottom: 20px;
padding: 15px;
border-radius: 4px;
border: 1px solid #e1e8ed;
background-color: #fff;
}

.test-title {
font-weight: 500;
margin-bottom: 10px;
color: #4a90e2;
}

.test-details {
font-family: 'Courier New', Courier, monospace;
font-size: 13px;
margin-bottom: 8px;
}

.test-status {
font-weight: 500;
padding: 4px 8px;
border-radius: 4px;
display: inline-block;
}

.test-status.passed {
background-color: #d4edda;
color: #155724;
}

.test-status.failed {
background-color: #f8d7da;
color: #721c24;
}

.copy-btn {
background-color: #28a745;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
margin-left: 10px;
transition: background-color 0.3s;
}

.copy-btn:hover {
background-color: #218838;
}

@media (max-width: 768px) {
body {
padding: 10px;
}

.content {
padding: 20px;
}

.btn {
width: 100%;
margin-right: 0;
}
}
</style>
</head>

<body>
<div class="container">
<div class="header">
<h1>浏览器端AES-256-CBC加解密演示</h1>
</div>

<div class="content">
<!-- 手动加密解密区域 -->
<div class="section">
<div class="section-title">手动加密解密</div>

<div class="form-group">
<label for="key">密钥 (Password/Key):</label>
<input type="text" id="key" placeholder="请输入密钥" value="260880">
</div>

<div class="form-group">
<label for="plaintext">明文数据:</label>
<textarea id="plaintext" placeholder="请输入要加密的明文数据">123</textarea>
</div>

<div class="form-group">
<label for="ciphertext">密文数据:</label>
<textarea id="ciphertext" placeholder="请输入要解密的密文数据"></textarea>
</div>

<button class="btn" onclick="encryptData()">加密</button>
<button class="btn btn-secondary" onclick="decryptData()">解密</button>

<div id="manual-result" class="result"></div>
</div>

<!-- 自动测试区域 -->
<div class="section">
<div class="section-title">自动测试</div>
<button class="btn" onclick="runTests()">运行所有测试</button>
<div id="test-results" class="test-results"></div>
</div>
</div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>
<script>
/**
* AES加密解密工具类
* 使用CryptoJS实现AES-256-CBC加密解密
* 包含PKCS7填充和PBKDF2密钥派生功能
*/
const AESCrypto = {
// 常量定义
BLOCK_SIZE: 16, // AES块大小(字节)
KEY_SIZE: 256 / 32, // 密钥大小(WordArray单位)
ITERATIONS: 100, // PBKDF2迭代次数
SALT_SIZE: 16, // 盐大小(字节)
IV_SIZE: 16, // IV大小(字节)

/**
* PKCS7填充函数
* @param {CryptoJS.lib.WordArray} wordArray - 要填充的数据
* @param {number} [blockSize=16] - 块大小
* @returns {CryptoJS.lib.WordArray} 填充后的数据
*/
pkcs7Pad: function(wordArray, blockSize = this.BLOCK_SIZE) {
if (!wordArray || typeof wordArray.sigBytes !== 'number') {
throw new Error('Invalid input: wordArray must be a valid CryptoJS WordArray');
}

const padding = blockSize - (wordArray.sigBytes % blockSize);
const paddingWords = [];
const paddingWord = ((padding & 0xff) << 24) | ((padding & 0xff) << 16) | ((padding & 0xff) << 8) | (padding & 0xff);

for (let i = 0; i < padding / 4; i++) {
paddingWords.push(paddingWord);
}

return wordArray.clone().concat(CryptoJS.lib.WordArray.create(paddingWords, padding));
},

/**
* PKCS7去填充函数
* @param {CryptoJS.lib.WordArray} wordArray - 要去填充的数据
* @returns {CryptoJS.lib.WordArray} 去填充后的数据
*/
pkcs7Unpad: function(wordArray) {
if (!wordArray || typeof wordArray.sigBytes !== 'number') {
throw new Error('Invalid input: wordArray must be a valid CryptoJS WordArray');
}

const sigBytes = wordArray.sigBytes;
if (sigBytes === 0) {
throw new Error('Invalid input: wordArray is empty');
}

// 获取最后一个字节作为填充长度
const lastWord = wordArray.words[Math.floor((sigBytes - 1) / 4)];
const padding = lastWord & 0xff;

// 验证填充长度
if (padding < 1 || padding > this.BLOCK_SIZE) {
throw new Error('Invalid PKCS7 padding: padding length out of range');
}

// 验证所有填充字节
for (let i = sigBytes - padding; i < sigBytes; i++) {
const currentWord = wordArray.words[Math.floor(i / 4)];
const currentByte = (currentWord >> (24 - (i % 4) * 8)) & 0xff;
if (currentByte !== padding) {
throw new Error('Invalid PKCS7 padding: inconsistent padding bytes');
}
}

// 创建去填充后的数据
return CryptoJS.lib.WordArray.create(wordArray.words, sigBytes - padding);
},

/**
* 使用PBKDF2派生密钥
* @param {string} pinCode - 密码/密钥
* @param {CryptoJS.lib.WordArray} salt - 盐值
* @returns {CryptoJS.lib.WordArray} 派生的密钥
*/
deriveKeySecure: function(pinCode, salt) {
if (!pinCode || !salt) {
throw new Error('Invalid input: pinCode and salt are required');
}

return CryptoJS.PBKDF2(pinCode, salt, {
keySize: this.KEY_SIZE,
iterations: this.ITERATIONS,
hasher: CryptoJS.algo.SHA256
});
},

/**
* 加密数据
* @param {string} pinCode - 密码/密钥
* @param {string} data - 要加密的明文数据
* @returns {string} Base64编码的加密结果
*/
encrypt: function(pinCode, data) {
try {
if (!pinCode) {
throw new Error('Invalid input: pinCode and data are required');
}

// 生成随机盐和IV
const salt = CryptoJS.lib.WordArray.random(this.SALT_SIZE);
const iv = CryptoJS.lib.WordArray.random(this.IV_SIZE);

// 派生密钥
const key = this.deriveKeySecure(pinCode, salt);

// 转换数据并填充
const dataWA = CryptoJS.enc.Utf8.parse(data);
const paddedData = this.pkcs7Pad(dataWA);

// 执行加密
const encrypted = CryptoJS.AES.encrypt(paddedData, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.NoPadding
});

// 拼接盐、IV和密文并Base64编码
return CryptoJS.enc.Base64.stringify(
salt.clone().concat(iv).concat(encrypted.ciphertext)
);
} catch (error) {
console.error('Encryption failed:', error);
throw error;
}
},

/**
* 解密数据
* @param {string} pinCode - 密码/密钥
* @param {string} encryptedBase64 - Base64编码的加密数据
* @returns {string} 解密后的明文数据
*/
decrypt: function(pinCode, encryptedBase64) {
try {
if (!pinCode || !encryptedBase64) {
throw new Error('Invalid input: pinCode and encryptedBase64 are required');
}

// 解析Base64数据
const encryptedData = CryptoJS.enc.Base64.parse(encryptedBase64);

// 验证数据长度
if (encryptedData.sigBytes < this.SALT_SIZE + this.IV_SIZE) {
throw new Error('Invalid encrypted data: data too short');
}

// 提取盐、IV和密文
const salt = CryptoJS.lib.WordArray.create(
encryptedData.words.slice(0, this.SALT_SIZE / 4),
this.SALT_SIZE
);
const iv = CryptoJS.lib.WordArray.create(
encryptedData.words.slice(this.SALT_SIZE / 4, (this.SALT_SIZE + this.IV_SIZE) / 4),
this.IV_SIZE
);
const ciphertext = CryptoJS.lib.WordArray.create(
encryptedData.words.slice((this.SALT_SIZE + this.IV_SIZE) / 4),
encryptedData.sigBytes - this.SALT_SIZE - this.IV_SIZE
);

// 派生密钥
const key = this.deriveKeySecure(pinCode, salt);

// 执行解密
const decrypted = CryptoJS.AES.decrypt({ ciphertext: ciphertext }, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.NoPadding
});

// 去填充并转换为字符串
const unpaddedData = this.pkcs7Unpad(decrypted);
return CryptoJS.enc.Utf8.stringify(unpaddedData);
} catch (error) {
console.error('Decryption failed:', error);
throw error;
}
}
};

/**
* 加密数据并显示结果
*/
function encryptData() {
const key = document.getElementById('key').value;
const plaintext = document.getElementById('plaintext').value;
const resultDiv = document.getElementById('manual-result');

try {
const encrypted = AESCrypto.encrypt(key, plaintext);
document.getElementById('ciphertext').value = encrypted;
resultDiv.innerHTML = `加密成功: <br><strong>密文:</strong> ${encrypted}`;
resultDiv.className = 'result success';
} catch (error) {
resultDiv.innerHTML = `加密失败: ${error.message}`;
resultDiv.className = 'result error';
}
}

/**
* 解密数据并显示结果
*/
function decryptData() {
const key = document.getElementById('key').value;
const ciphertext = document.getElementById('ciphertext').value;
const resultDiv = document.getElementById('manual-result');

try {
const decrypted = AESCrypto.decrypt(key, ciphertext);
resultDiv.innerHTML = `解密成功: <br><strong>明文:</strong> ${decrypted}`;
resultDiv.className = 'result success';
} catch (error) {
resultDiv.innerHTML = `解密失败: ${error.message}`;
resultDiv.className = 'result error';
}
}

/**
* 添加测试结果到UI
* @param {string} title - 测试标题
* @param {string} details - 测试详细信息
* @param {boolean} passed - 是否通过
*/
function addTestResult(title, details, passed) {
const testResultsDiv = document.getElementById('test-results');
const testItem = document.createElement('div');
testItem.className = 'test-item';

const testTitle = document.createElement('div');
testTitle.className = 'test-title';
testTitle.innerHTML = title;

const testDetails = document.createElement('div');
testDetails.className = 'test-details';
testDetails.innerHTML = details.replace(/\n/g, '<br>');

const testStatus = document.createElement('div');
testStatus.className = `test-status ${passed ? 'passed' : 'failed'}`;
testStatus.textContent = passed ? '通过' : '失败';

testItem.appendChild(testTitle);
testItem.appendChild(testDetails);
testItem.appendChild(testStatus);
testResultsDiv.appendChild(testItem);
}

/**
* 运行所有测试
*/
function runTests() {
// 清空之前的测试结果
document.getElementById('test-results').innerHTML = '';

console.log('=== AESCrypto 测试开始 ===');

let testCount = 0;
let passedCount = 0;

// 测试1: 基本功能测试
testCount++;
try {
const pinCode1 = '260880';
const data1 = '123';

const encrypted1 = AESCrypto.encrypt(pinCode1, data1);
const decrypted1 = AESCrypto.decrypt(pinCode1, encrypted1);

const passed = decrypted1 === data1;
if (passed) passedCount++;

const details = `密钥: ${pinCode1}\n明文: ${data1}\n密文: ${encrypted1}\n解密后: ${decrypted1}`;
addTestResult(`测试${testCount} - 基本功能测试`, details, passed);
} catch (error) {
addTestResult(`测试${testCount} - 基本功能测试`, error.message, false);
}

// 测试2: 复杂密钥和中文数据测试
testCount++;
try {
const pinCode2 = 'OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN';
const data2 = '这是一段中文测试数据';

const encrypted2 = AESCrypto.encrypt(pinCode2, data2);
const decrypted2 = AESCrypto.decrypt(pinCode2, encrypted2);

const passed = decrypted2 === data2;
if (passed) passedCount++;

const details = `密钥: ${pinCode2}\n明文: ${data2}\n密文: ${encrypted2}\n解密后: ${decrypted2}`;
addTestResult(`测试${testCount} - 复杂密钥和中文数据测试`, details, passed);
} catch (error) {
addTestResult(`测试${testCount} - 复杂密钥和中文数据测试`, error.message, false);
}

// 测试3: 空数据测试
testCount++;
try {
const pinCode3 = '260880';
const data3 = '';

const encrypted3 = AESCrypto.encrypt(pinCode3, data3);
const decrypted3 = AESCrypto.decrypt(pinCode3, encrypted3);

const passed = decrypted3 === data3;
if (passed) passedCount++;

const details = `密钥: ${pinCode3}\n明文: (空字符串)\n密文: ${encrypted3}\n解密后: (空字符串)`;
addTestResult(`测试${testCount} - 空数据测试`, details, passed);
} catch (error) {
addTestResult(`测试${testCount} - 空数据测试`, error.message, false);
}

// 测试4: 特殊字符测试
testCount++;
try {
const pinCode4 = '260880';
const data4 = '!@#$%^&*()_+-=[]{}|;:,.<>?';

const encrypted4 = AESCrypto.encrypt(pinCode4, data4);
const decrypted4 = AESCrypto.decrypt(pinCode4, encrypted4);

const passed = decrypted4 === data4;
if (passed) passedCount++;

const details = `密钥: ${pinCode4}\n明文: ${data4}\n密文: ${encrypted4}\n解密后: ${decrypted4}`;
addTestResult(`测试${testCount} - 特殊字符测试`, details, passed);
} catch (error) {
addTestResult(`测试${testCount} - 特殊字符测试`, error.message, false);
}

// 测试5: 长文本测试
testCount++;
try {
const pinCode5 = '260880';
const data5 = '这是一段较长的测试文本,用于测试AES加密解密的性能和正确性。这段文本包含了多种字符,包括中文、英文、数字和特殊符号。';

const encrypted5 = AESCrypto.encrypt(pinCode5, data5);
const decrypted5 = AESCrypto.decrypt(pinCode5, encrypted5);

const passed = decrypted5 === data5;
if (passed) passedCount++;

const details = `密钥: ${pinCode5}\n明文长度: ${data5.length} 字符\n密文长度: ${encrypted5.length} 字符\n解密后长度: ${decrypted5.length} 字符\n解密后与明文一致: ${passed}`;
addTestResult(`测试${testCount} - 长文本测试`, details, passed);
} catch (error) {
addTestResult(`测试${testCount} - 长文本测试`, error.message, false);
}

// 测试6: 错误密钥测试
testCount++;
try {
const pinCode6 = '260880';
const wrongKey = 'wrongkey';
const data6 = '123';

const encrypted6 = AESCrypto.encrypt(pinCode6, data6);
// 使用错误密钥解密,应该失败
const decrypted6 = AESCrypto.decrypt(wrongKey, encrypted6);

// 这里应该抛出错误,如果没有抛出则测试失败
addTestResult(`测试${testCount} - 错误密钥测试`, '使用错误密钥解密时没有抛出预期的错误', false);
} catch (error) {
// 预期应该抛出错误,所以测试通过
passedCount++;
addTestResult(`测试${testCount} - 错误密钥测试`, `使用错误密钥解密时正确抛出错误: ${error.message}`, true);
}

// 显示测试总结
const summary = document.createElement('div');
summary.className = 'test-item';
summary.innerHTML = `
<div class="test-title">测试总结</div>
<div class="test-details">
总测试数: ${testCount}<br>
通过测试: ${passedCount}<br>
失败测试: ${testCount - passedCount}<br>
通过率: ${((passedCount / testCount) * 100).toFixed(2)}%
</div>
<div class="test-status ${passedCount === testCount ? 'passed' : 'failed'}">
${passedCount === testCount ? '全部通过' : '部分失败'}
</div>
`;
document.getElementById('test-results').appendChild(summary);

console.log(`=== AESCrypto 测试结束 ===`);
console.log(`总测试数: ${testCount}`);
console.log(`通过测试: ${passedCount}`);
console.log(`失败测试: ${testCount - passedCount}`);
console.log(`通过率: ${((passedCount / testCount) * 100).toFixed(2)}%`);
}

// 页面加载完成后自动运行测试
window.addEventListener('load', function() {
runTests();
});
</script>
</body>

</html>


2. Request and Response Protocol Data Format

2.1 Request header

VariableTypeRequiredDescription
x-p-business-idStringYThe current business ID, Specify the ECR device to receive orders for a certain Business
x-device-snStringYThe serial number of the ecr terminal payment device
x-request-idStringYEvery time communication takes place, it is crucial to ensure that the Request ID is a unique UUID.

2.2 Request data structure

Request JSON
VariableTypeRequiredDescription
versionStringYCurrent communication protocol version number
actionenumYActions: Pair, DeviceInfo, Sale, ...
dataStringYEncrypted data
Request "data" structure
VariableTypeRequiredDescription
headerObjectYProtocol header
bodyObjectNProtocol body
Request "data.header" structure
VariableTypeRequiredDescription
requestIDUUIDYRequest ID: Every time communication takes place, it is crucial to ensure that the Request ID is a unique UUID. In the event of a response, the corresponding identifier will be returned in the response header as the "responseID".
clientDeviceSNStringYClient device serial number
timestampdatetimeYThe timestamp of the current request
Example:

/*
Encrypt the original data:
{
"header": {
"requestID": "9c07d8d7-2a43-4a29-9c6d-6b8d8f7d44e5",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
},
"body": {
"pairUuid": "3f37e6c0-bf6e-4c00-b1fa-b2bd5e1d6a3b"
}
}
*/

{
"version": "2.0",
"action": "Pair",
"data": "WJq3v/ZX/aMMR45WFqfs9BZ2J93EtSTYQh4JOD17ldQkzXi6ohsjxCdl4mpvAOqhFyWPVuEadUubmRzfACUAQpqledyJhOdtQTMlr4KnZXBJw6g3TOFTeKe1I/DqMiEEG0X9BEelUNS+0+FpaoWN1mVkuKEpt8XMGrHyA+M4XbaMwjQ3fMeoR77FULPvM9MCkw6B3QTGONMml51X8pqXsBYTrcpS5SLFVvdL5e+1CcIuVvliyrV3MDd+cwlSjHNIoaLwDEgu9wDNjGTYe1L8Ww=="
}

2.3 Response data structure

Request JSON
VariableTypeRequiredDescription
versionStringYCurrent communication protocol version number
actionenumYActions: DeviceInfo, Sale, PreAuth, Abort, Void, Refund
dataStringYEncrypted data
Response "data" structure
VariableTypeRequiredDescription
headerObjectYProtocol header
bodyObjectNProtocol body
Response "data.header" structure
VariableTypeRequiredDescription
responseIDStringYThe response ID in the response Header is derived from the request ID in the request header.
serverDeviceSNStringYThe serial number of the terminal payment device
timestampdatetimeNThe timestamp of the current request
Example:

/*
Encrypt the original data:
{
"header": {
"responseID": "9c07d8d7-2a43-4a29-9c6d-6b8d8f7d44e5",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"pairUuid": "3f37e6c0-bf6e-4c00-b1fa-b2bd5e1d6a3b",
"ackUuid": "4d366618-49cf-4f93-bd23-25388a573b0c"
}
}
*/

{
"version": 2.0,
"action": "Pair",
"data": "G6RaFsGPTiVzAYsUTu/gY1Igjv+4THb1tZ7vwXWP9f1CYRRrNKKuz4Op7ai9xCqKCdBymnO/YAQTB9egq10DIp/mxQ4pG1dGyL+Erkd91G4xYJd9S7iXNqnCwEn2wOhMIn3sP0H6vgTzoGX9ZOi59pLhuGqYTbHBPvDIkavEIweWWVQjEUdQn7HG0ymqxq4O36giOlh5NldSPwH5LjbnOamEm+Y41jIW/dRexnd7hhKkF/TrZg2lDYKOry9NflNzoMPHiB2/7YgVVmgVfBysW9dqqNRiJXxYLOD6UGoJlQqsICeiidKm6SYL4dkKHYniFEnZ0a5KGdxZs7viSahmiA=="
}


3. Interface Protocol

3.1 Pair

After the customer device acquires the 6-digit pairing code, it uses the "Pair" protocol for pairing. After the Wonder terminal receives a pairing request, it will return a UUID identifier, which will be used by the "Ack" protocol.

  • Action: Pair
  • Pin Code: pinCode1

Request "data.body" structure

VariableTypeRequiredDescription
pairUuidUUIDYPair the uuid identifier
Example:

/*
Pin Code: pinCode1
Encrypt the original data:
{
"header": {
"requestID": "9c07d8d7-2a43-4a29-9c6d-6b8d8f7d44e5",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
},
"body": {
"pairUuid": "3f37e6c0-bf6e-4c00-b1fa-b2bd5e1d6a3b"
}
}
*/

{
"version": "2.0",
"action": "Pair",
"data": "KhGmDIJZQXsNHrLM1hDB/kjPjlSpmUQVNIrRLEAptCHb+GHiqdZTnfDRWJVBJDzTyLtqDXLJYRR3433sIEm7hBvpI8vZ4WeTIxcp1BUd4GwRjutbUMCQ8vc5GTlu8aWvSoChYWeHXIu5MmWXbfkWe8AMAHLtnjuvrZfV17mTlvX+09hskf5zCcFKKXVq6qA24o4d5crbIoKEmRI0K94YSPo99N9mEdnAVdh5xNxQmzsp1JlKMnxQGIy2K1HuUmabW1JLWID/In4sADJDdRk2069oYrP1PWYUqKKoahtH7GNQqJ0Syux/IykdoXVZ2dmn"
}

Response "data.body" structure

VariableTypeRequiredDescription
pairUuidUUIDYPair the uuid identifier
ackUuidUUIDYAck the uuid identifier
pinCodeStringYIn the test code, it is pinCode2, which is used in the Ack interface and the business interface
Example:

/*
Pin Code: pinCode1
Encrypt the original data:
{
"header": {
"responseID": "9c07d8d7-2a43-4a29-9c6d-6b8d8f7d44e5",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"pairUuid": "3f37e6c0-bf6e-4c00-b1fa-b2bd5e1d6a3b",
"ackUuid": "4d366618-49cf-4f93-bd23-25388a573b0c",
"pinCode": "OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN"
}
}
*/

{
"version": 2.0,
"action": "Pair",
"data": "N7rbBZmxrGP5kh7vUaGOs1CslAJVsa53OKmEjdkx72ulWIptVPuJNCfz+GCIrt7E66S+nG5uMpNkj7XOtj2IppH/WwUQQMSBVsFc9meSy0+GjOARJ61W9CXxVu2sBMUNWGgzuxd1bhGmXD/GNTHLuuzFZJv0ANIR26tf+MyUs19a/cYxhHba8tgcIYQG/FLEHK7hI2p3hX0ETESxEDDyogVP0a8F050Jua5nIjU/BBfhfC1g0/Iu5q+oSN/caZcZyO6F/a5dF6EXPDbJY0yr8QDsH8nr8mEfaO3HS7gtozcVIylsmbXNftAzlj4Ex1768VeVHXVvfimjUzGy4HsvxiJBAQixAkKR/nQVguyCSWojmOXwDFm5jjjmoXTSvZxsrYuogke4gAlW055leR9fGiHesXoPL1zyzWSR1EeuxtAGZB1V2B9yUKjRhc5GPTWH"
}

3.2 Ack

After the client terminal initiates the pairing, it will receive an "ackUuid" identifier. This protocol needs to carry the "ackUuid" identifier to confirm that the pairing has been successful.

  • Action: Ack
  • Pin Code: pinCode2

Request "data.body" structure

VariableTypeRequiredDescription
ackUuidUUIDYThe Wonder device will use this UUID to confirm whether the pairing was successful
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"requestID": "73a95cfe-b0f1-42b3-82d1-5a640f61e359",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
},
"body": {
"ackUuid": "4d366618-49cf-4f93-bd23-25388a573b0c"
}
}
*/

{
"version": "2.0",
"action": "Ack",
"data": "1Rlzdz9YVYhK9cI0tqodWqay2D8t0vs3slnvVn0lW5G2EqFcfQtC/4j7oQ+X/MOvADkbVGVDREB54LxJWK5UtzNVx1+z5R/ydgYryjcUuI4p724nsggY0lIbIBE+6yCDZQE6iXYZYAVAUkdyukNB18WbmqEK0+V+uPt/NWc4H0t5drhK+nz8uu62h4PT/Fxma5/ZcnBbRqjSMe1nUJmlqY0vKmJhhZ17N9M85rgh/JUsMebNMmERR6XDbnuls4bKY4hffSVzNbWHjBWjdfX60KU2r7SBE8HiEKS41FcVDhl2dmVcNybz/+RTSxMsnEvA"
}

Response "data.body" structure

VariableTypeRequiredDescription
deviceStatusStringYPayment device transaction status: Free / Busy
Free: The current device is idle and available for new transactions;
Busy: The current device is occupied with an ongoing transaction and is not available for other transactions at the moment.
networkStatusStringYThe current network connection status of the payment device: Connected / Disconnected
softwareVersionStringYThe software version of the payment device
businessIDStringYThe response ID in the response Header is derived from the request ID in the request header.
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "73a95cfe-b0f1-42b3-82d1-5a640f61e359",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"deviceStatus": "Free",
"networkStatus": "Connected",
"softwareVersion": "1.0.0(188)",
"businessID": "ff467f02-5b69-45f3-81aa-bffcca55fe8f"
}
}
*/

{
"version": 2.0,
"action": "Ack",
"data": "thygIk5FDezl1xaeyOFkwduPBRl8PS65YQ5+aa1bLCT6gjIVGbjGsQlvkOl+24To6ztvk3CtJ5Jgeimy93RuW3cGYflth+Eb8A2031pbUa8918aJ08lHhVmbeajnWoaN9iWmExBuqkN4EA76SB6ELELwJQR3z0xlfREuhDyhlhIeBTs5dy+UptkKzIpHzcMB6aPL37qF+TIAW6M4B7hLniTM5RfCmFwQjDRNrj78pwA8teLrvPrGSXceQnbMxlk2BXl1BhVnhTSxVh8iP/KtLi9MxO4YvSfBsrfOkwrFLNIh3SardG0V2QVgGwdfKxmCSIf4GxuDF3bJz8XM8CowAogC0dY5zea4Ms2ifblCI13dD/uMJF3qrS36Xuj+LN7lO3UYWYtNzBy0vYo45PrZ/5Zh4WOeZ5sZk43Ycotj+fk="
}

3.3 Device Info

  • Action: DeviceInfo
  • Pin Code: pinCode2

Request "data.body" structure

This request has no body

Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"requestID": "2c7f32e1-b9e4-4b34-96cc-15c51289f69b",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
}
}
*/

{
"version": "2.0",
"action": "DeviceInfo",
"data": "fZL3Z4ZlYRz5dt5ls0orrG5Pw1vdHxK+35tOc1aDIyInrHErmJRfeohzuviFFb7FuaxMZYPKU2GEMVIq8BvS3ua2xAj1CWHnduaO0YGTHfcuYTOTZxy3CZHvMtphPux+LZ2n3QlkhRPXeMwDlcOeaq1lKLerkcQf1SDSK14MvrTVg/NuB3BArPVmZsX9zBZ1pDrc7ixr4O/yNLD6RR/9JOKt3XWYqAJyztN06hYfSSI="
}

Response "data.body" structure

VariableTypeRequiredDescription
deviceStatusStringYPayment device transaction status: Free / Busy
Free: The current device is idle and available for new transactions;
Busy: The current device is occupied with an ongoing transaction and is not available for other transactions at the moment.
networkStatusStringYThe current network connection status of the payment device: Connected / Disconnected
softwareVersionStringYThe software version of the payment device
businessIDStringYThe response ID in the response Header is derived from the request ID in the request header.
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "2c7f32e1-b9e4-4b34-96cc-15c51289f69b",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"deviceStatus": "Free",
"networkStatus": "Connected",
"softwareVersion": "1.0.0(188)",
"businessID": "ff467f02-5b69-45f3-81aa-bffcca55fe8f"
}
}
*/

{
"version": "2.0",
"action": "DeviceInfo",
"data": "+AGm65vmYsIBpb0oOlvyCkcJ/BurpmzLL7LusZW2mlfmEE3bYAD8hbwbrOshjozgFtkL+oMSrSfvs8rxHxdr5RU9WVCBgfognPaJj+9XnNJ43vnY7cjr5LvN5OZg8HNEiRYRQipGkjlPqiqWpyYCHs1nSIFoR/KSUvIokFKDY5USySXSBs5cp+vdbO6THLjWPYrgywQ8aBfNdaUUEMZEVURRhoQYY0frhko6I2i6iatD7b4BiO2W+J8ycDClo+3QBRmRUPjZA6w5CobbWXckYZO2GxWDg1X3i8IJqx2qioVew9mzYeJ74a4/6EIiUy/ebqGOqHeVTGEuCa0jogZkVixbYBoBbb3yhdLyPa0s8aPGatYmO5XzUTpsXXoDwmXf00yJdgE5Q7vNmxwv94jSp4SAVxB8gR9yvO3iLXqG+3I="
}

3.4 Sale

  • Action: Sale
  • Pin Code: pinCode2

Request "data.body" structure

VariableTypeRequiredDescription
referenceIDStringYReference ID: Every time a transaction request is initiated, it is crucial to ensure the uniqueness of this ID. Failure to do so will render any subsequent operations on the transaction invalid.
customerOrderIDStringNThe order ID of the customer's transaction
currencyStringYExample: HKD / USD / RMB
amountStringYSale amount
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"requestID": "5debf769-49d7-4c9b-b6f4-8a9d90e1a874",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
},
"body": {
"referenceID": "f8b13b22-16ca-4a87-95a4-df4bebf09ee1",
"customerOrderID": "e246c1cc-02f6-4ac5-b7fb-066cb2b2f5b1",
"currency": "HKD",
"amount": "10.20"
}
}
*/

{
"version": "2.0",
"action": "Sale",
"data": "OE9dcJmLIlqcsAeVyLx1JW7T60f+o32mH+miGIyZRQkLdDuutmQGw/pnYDYPyBOgvCiES4ySbj1UPrUTJWRJaxGTqtP4mI/faqS6iKjPbsfSa2gg8DGc9CnBBHZ6tM902yMJ8n1Jwn0wtfqs3v0NPL3iPb+C5tSqJHpBHwuInndHy/u/Rg/SK+AiY8946eqhYfvyd1mPzl1fMDYErs+6L1ObQkPGiFmWQIuXk0xgdsl4oe7TS4Xci7+33gHpMPLgYMMEztZj6y7A8cUPXXVNHSeqG2+A1EcutsRHJTD5J43W3rsIZH3TMaeiLkLOWY4poHU7RrFoGBUOIh+bP4LtOgpd9+c9wb//cEKAZbLY4AqxyL3NEyySYaZYBUaDhdsd9A9TO2DBrCUm2Wl03LmpuDdiLfzwwrJj9S4Ms6JsCmKrFE7w94n/8/DWD9zTDOKD"
}

Response "data.body" structure

VariableTypeRequiredDescription
statusStringYResponse status: Success / Failed / Pending
errorCodeStringY
errorMessageStringY
customerOrderIDStringNThe order ID of the customer's transaction
currencyStringNExample: HKD / USD / RMB
amountStringNSale amount
paymentMethodStringNPayment method
paymentEntryTypeStringNPayment entry types, Example: contactless
rrnStringNReceiver Reference Number
brnStringNBindo Reference Number
transactionTypeStringNTransaction type: Sale / PreAuth / Void / Refund
transactionTimeDatetimeNTransaction Time
creditCardObjectN
creditCard.panPrefix6DigitsStringYFirst 6 digits of the credit card number
creditCard.panLast4DigitsStringYLast 4 digits of the credit card number
creditCard.panHashStringYSHA512
creditCard.panTokenStringY
Example 1:

When the status is Pending


/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "5debf769-49d7-4c9b-b6f4-8a9d90e1a874",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"status": "Pending",
"errorCode": "",
"errorMessage": ""
}
}
*/

{
"version": "2.0",
"action": "Sale",
"data": "CcDYsa/fPAjhaaTi5e0SQHJ5AGeWrfhu+D70RJwU9vizGFB38D9j65iEUbBQqs7qbjOQ9AGaBkhNhBWNYUXtdDT5FT9R/2aSLodTgpTPbsWNGhkihyaaVQ+9kN/RjL/frPrvKV1VQsRDEG783RKRLY5Uz0RsSGLXbqkW0drzKxnAvAs13KlcqrfTe0rHNnZ+fKzuW7imxytn1nXKUtGciIXCE+NzXvRSmYbk0WPM+hTCM2WbC+Vul8vD3++vp4v7u4z3d+A7LRcE30W3q6TZKciZ9pnau1A4eVjxAY5EJ93uMWNnny5/yDOE2s1gKHS1"
}

Example 2:

When the status is Failed


/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "5debf769-49d7-4c9b-b6f4-8a9d90e1a874",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"status": "Failed",
"errorCode": "5xxxx",
"errorMessage": "The equipment is being traded"
}
}
*/

{
"version": "2.0",
"action": "Sale",
"data": "aDmtvHICThbeeWzsusOZbKWWwJOI1PZC5mUHufTvsVr8vO8UyqBw99XfujjCJNq6ibse10OsBLbGc488Ty7qZW/aO8cJi/KQgqVhPU84pQ1wmfbbbZODvlV0PmD9JU6dqjU2BvChhNfFVXKYF6AGXjMh6/NFQlY4G59w0kI1vgNYyRHohoyqHBX9qm4+MUlb0f010DtTPZKMzfRL//KBilJjctok9CWz9CjRim39D969UoS4WLm7x1eXAC/DMPaw2KM/MlUp05BFzcArZlgf1bCtxhvL1TVcwhVQSLHtxYk5Mrc8rIeLMZ0I8Yw5JsbXATMgSmcz+KzaHSwlg7TtB+8rpA1VLelBf0PZmPXwOKU="
}

Example 3:

When the status is Success


/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "5debf769-49d7-4c9b-b6f4-8a9d90e1a874",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"status": "Success",
"errorCode": "",
"errorMessage": "",
"customerOrderID": "e246c1cc-02f6-4ac5-b7fb-066cb2b2f5b1",
"currency": "HKD",
"amount": "10.20",
"paymentMethod": "visa",
"paymentEntryType": "contactless",
"rrn": "3263492852830699521",
"brn": "3263492852495159296",
"transactionStatus": "Success",
"transactionTime": "2023-06-30T09:08:52+00:00",
"creditCard": {
"panPrefix6Digits": "555555",
"panLast4Digits": "1234",
"panHash": "xxxxxxx",
"panToken": ""
}
}
}
*/

{
"version": "2.0",
"action": "Sale",
"data": "7Z12NF2oZU9zZvQkxAUsWe6fgHZux1IlYJ56DRoK6IpSRdizzq4+Fb5dosmaZZo1rere/21Dxq88IXKKS0yRc3qbaLKwMmRInInvoeSNgOLeSBhAjk8x8P5KJ6m46qzxXOB79SNSxrW+phn5nDiuJ8K/RHYN6yTi0ODRul9fxdZfj0HV/WCDq7IoSYnoDNBuAdm6o3DNcYqB2goGWIJseCpsEojEig58ZgEb5oC9WEUIajhj5FEstEJ2xeUh5DFzUyRryQ1XGO2VGh0eziofOCdYryyjLFD1VkOOP2dtqYJm5Pr1q3GMO5NG67T/E6FLLyP0SWioS+6kLG8qnUiMp2hW4FWK3+BA4xJxHRxXeoh0a/kJKZoe+r+WJow9cafcsLdi0Klv64puK35m6Lgn1Xck28vCaZ+2r/ECPcCnfCjZpTvGB60RhzCBJXY04Sspw40rsmKeS4RJVV4r7SdJBVFX5qtvgdisUTBvgJgIQOHzuTCInTh6CY2HtnzTpzg06KNoYMYN7iwnXE6rIi9c5jCj0T/AWWlX3FpH1x9L4Ie+v2fzNK9D2brlrieGF7v1PbWw1aAvw7MEtdA4k13srOx9ZwQvVc0RQU+Jrom34Gj+QaOMk2XbIZUm6618K8P2GUMrlGOouPEm+WAVFokZCQMNLzi+NXp4u1tsZOwbq3ns0XiVvSAi4hj+c0hmwxbtcJXk+p/ElfnhTW2uMGvgQ7pqyuEO+3dxAWqZ/h2dMiYRx/fYXXVrCRCiBwrdo/kKH2KWouEmIVGrPhoAhhgJMBtIAWav2p0aNnf5RSdkaNhoCMMKHVVdEXBJ5qGQb4df"
}

3.5 Abort

  • Action: Abort
  • Pin Code: pinCode2

Request "data.body" structure

This request has no body

Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"requestID": "c5bf3cbe-a146-4f8c-bb8e-209c1e7b8437",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
}
}
*/

{
"version": 2.0,
"action": "Abort",
"data": "uKd8e4L5AULV+jo/XPg4bzMzppIkvDN8NLoB3NAhUwgB+WZ5yMJBifa9gH/nNh/PJe9Kw96L5BFg0tTjK6WqiL4U35DxDbE+99G+PLRK4AJhhfsEDHwMYZGxILtWItM+9+SGD+zoqLDx/72Jz8IcJhVb8fkPHiECllL/Lyp7Y66TRe59OjvCOov4hHxgh5Cwe8m566LK+2gxCgiUj6sdDZaWngBBx4V/4EG2IkZe2lc="
}

Response "data.body" structure

VariableTypeRequiredDescription
statusStringYResponse status: Success / Failed / Pending
errorCodeStringY
errorMessageStringY
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "c5bf3cbe-a146-4f8c-bb8e-209c1e7b8437",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"status": "Success",
"errorCode": "",
"errorMessage": ""
}
}
*/

{
"version": 2.0,
"action": "Abort",
"data": "Agv/204TIuODU9mRa0g31lG9QKpqY/qD+PSCsN9NjYaOZOW46B9IGL/4qMRIjEo7sMtyMMqwcaMyhoXo6VlvrWwF+nmrdO2HP0QwMYjroYUaTIc8yfX8Edq3UhFG69eZTM1oaX4i8+f/x2PxdsEv+6gIKEqjwHITNG9nFn29ZtNcOcMbJUud7/8SynQXgY9Sz5Q2XgAYrVgxK4WHKWltdktflKGe+Be0I6x6f5s2Gl4YWZFm+BtT3tzIIVUotmUkyxggw7a6PT/BnLWRKzv1Igth1HxMkyLhC6DoiO7+1Tq6/Lq9p2oXJUeCueOV4Z/i"
}

3.6 Void

  • Action: Void
  • Pin Code: pinCode2

Request "data.body" structure

VariableTypeRequiredDescription
orgReferenceIDStringYThe reference ID that was carried during the transaction made at that time.
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"requestID": "8e2c77fb-ff49-4c49-82f5-ae741cb7d3d9",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
},
"body": {
"orgReferenceID": "f8b13b22-16ca-4a87-95a4-df4bebf09ee1"
}
}
*/

{
"version": 2.0,
"action": "Void",
"data": "DOdyYB+YN2pT6M7kTImwlruw0Gdn5NHD0Cz3qAgcQaDSr66vQ1X8HtK2eDmeReQIcwjivvwR/+eHFriBT6MssLQLrVD6ZX9Kk427HGFHGuezs9AFd16RLTrl/rODHj3v0efolW8WDXDcz3uzZ3SyRkKCAWvpshL/y5ANLeSk/jAkFRQat/035jn5s80axaJlwEKPh3PNF8QHZY3OFAJqG1UaLMz/DGuteHl3kAKPWNHvUfdVClt+FgfFHvwk+e7njMez638BCMQD3MAxadv7RicdGjT3M+qVeTI+SnDJ4gJJmsPKm2kLz/ATU7xKDN+u"
}

Response "data.body" structure

VariableTypeRequiredDescription
statusStringYResponse status: Success / Failed / Pending
errorCodeStringY
errorMessageStringY
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "8e2c77fb-ff49-4c49-82f5-ae741cb7d3d9",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"status": "Success",
"errorCode": "",
"errorMessage": ""
}
}
*/

{
"version": 2.0,
"action": "Void",
"data": "wmNcblqksB4rvya2WETsBOJf9sg1/rD1W4xx64cfqHi44SVYqXvmBUNRtaGI4+UirFD67WMmpd3z6vgXZsPgfYnYbJm4calNpBAWqgUxgntjJzDm5YRTTZqCzsW16WDu81XozqSRopHUO6tXSPR+X9pxCAA6TKEM3gf1WibryIgcN+LTUjPnz3NvI8weIQCfZIJWDZiiXbIMPCQTXMTUAklxfbQtXgVmi3Eutt7pmmH+GmUOiJOq1ldSuCNUc2PnRIkVc30DAW9g8nIBmHJo887dzuHP/CeBlUgC4FETdUKM+UDvuNJAJl05lVZSeSTC"
}

3.7 Refund

  • Action: Refund
  • Pin Code: pinCode2

Request "data.body" structure

VariableTypeRequiredDescription
referenceIDStringYReference ID: Every time a transaction request is initiated, it is crucial to ensure the uniqueness of this ID. Failure to do so will render any subsequent operations on the transaction invalid.
orgReferenceIDStringYThe reference ID that was carried during the transaction made at that time.
currencyStringYExample: HKD / USD / RMB
amountStringYpreAuth amount
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"requestID": "0f7d24de-76fc-46f8-861b-2d0d31a2dd9e",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
},
"body": {
"referenceID": "97cc8c76-65e0-4bd2-9e16-9b9e09f65c42",
"orgReferenceID": "4b02c099-4dc9-4b30-bd2c-27bf3223df6b",
"currency": "HKD",
"amount": "10.20"
}
}
*/

{
"version": 2.0,
"action": "Refund",
"data": "9s+NYd52kApZBoNgI2PogmN02RP/CFmOM4lrFnAL0tTDiz/g8dlKhvNUby2uo8Yuui6OqRBHpPTkIR97ov9q5E93EWYsDSBqpEZuIx/FF5q05GR2BkEnWiYre1+ZhROnihycHQv8HXIHuihB+d+n4bGMtjxFyV4t9hbH43HBqtS+d6yXMBNObWA+WwIZKPwAUq+rnlvSfuIoeIUwoTy6GqhEK8R9I1El05Hc1Kg0KJBdGHlXLBYU+xkQvGPn3C1KRUG8lmRIzTXaIDbNw+4GAhq14IeyhXfzhS6JWysUza8XTOaXUiKYc3Ka4gb3jTt/ZynCTmjE0A/Za037nW4AFAZy478Bq/cqkgZP8qvVVd7qYxkqpe+dBM9eU5BhYSqkIGvpOiDiWTBy8TXqRfexRbkDAkRFm7QD/ng/P1dJO2Y="
}

Response "data.body" structure

VariableTypeRequiredDescription
statusStringYResponse status: Success / Failed / Pending
errorCodeStringY
errorMessageStringY
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "0f7d24de-76fc-46f8-861b-2d0d31a2dd9e",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"status": "Success",
"errorCode": "",
"errorMessage": ""
}
}
*/

{
"version": 2.0,
"action": "Refund",
"data": "NfjFtfEdlWXJ/sXqaApef8FQcjoOr8mZynJlBfOw5OdOgtvUUdB7GTbGJvNt6Ye94DsavJQhz5+drVUaSwZVTB8BVmBN/CsE2tfcPz3Bu9F59jzIPU9+AKMjp1/1aQ6/btm6bEcauWSZshQE+G3oVOgM0EgI/ZFGGN5n7i5OzW6tCWvLl9SvoaIXbsolp4AT9tzO51nKl8Plr0y7jTOatls6D4sSxPnLguuQJrqA9Q/wUMMYakwX+7MaedMIP0iitImsvoLOJRULTVLRhCbv0FebFZ/X1sDeSHe23yuLlnbdlhpSXjToRsWgCUtOLALc"
}

3.8 Query Transaction Status

  • Action: TransactionStatus
  • Pin Code: pinCode2

Request "data.body" structure

VariableTypeRequiredDescription
targetReferenceIDStringYThe reference ID that was carried during the transaction made at that time.
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"action": "TransactionStatus",
"requestID": "18fd2b62-6f65-40f2-8b94-88ef32f07a3f",
"clientDeviceSN": "126498561093",
"timestamp": "2025-11-12T10:11:04+00:00"
},
"body": {
"targetReferenceID": "f8b13b22-16ca-4a87-95a4-df4bebf09ee1"
}
}
*/

{
"version": 2.0,
"action": "TransactionStatus",
"data": "3U0hWqglZgydHjzniajpGTJcl2rjH8b1jINmfnDKq+c6ogfrhxVpjtY9AybhgmP9s4mMo2BvPLKMumyzFfZ8n+nInKQTMPUYvIB+TJqV9wdxhqORsfIH8o9hLJd9ot31opwxVdIqlGdU3S3qNzEeZQ4KmqcbyneolQv6niBkiHNf3dnyZHXv7gr6yY56P5g3gORRK82a2JZBkZGwPJj9Me1aazM7QImj1AiSzaBu9Q+fqSTcYvtF7JGe0rvWp6BGXoBdlN2MEJPC+UtK0ZLdolwtaX5HV6wLeXm+dRh/6BCC9cXugE0XY1WCFSqcqxs2C9yagn5fbMwd7ZhVJ2qewI9Mc2TCkBAYQcZX+RRDllE="
}

Response "data.body" structure

VariableTypeRequiredDescription
statusStringYResponse status: Success / Failed / Pending
errorCodeStringY
errorMessageStringY
...AnyYIt is consistent with the returned information of the current query transaction type
Example:

/*
Pin Code: pinCode2 (OvSdpyD2FoUNR5rNyte41QqZzR1Y4DVN)
Encrypt the original data:
{
"header": {
"responseID": "18fd2b62-6f65-40f2-8b94-88ef32f07a3f",
"serverDeviceSN": "NEXGO-N96-1170270945",
"timestamp": "2025-11-12T10:12:04+00:00"
},
"body": {
"status": "Success",
"errorCode": "",
"errorMessage": "",
"customerOrderID": "e246c1cc-02f6-4ac5-b7fb-066cb2b2f5b1",
"currency": "HKD",
"amount": "10.20",
"paymentMethod": "visa",
"paymentEntryType": "contactless",
"rrn": "3263492852830699521",
"brn": "3263492852495159296",
"transactionStatus": "Success",
"transactionTime": "2023-06-30T09:08:52+00:00",
"creditCard": {
"panPrefix6Digits": "555555",
"panLast4Digits": "1234",
"panHash": "xxxxxxx",
"panToken": ""
}
}
}
*/

{
"version": 2.0,
"action": "gBzyZALiwFJKCafXs52mAn0yishykDmpTHSSEy7i4HYVulo3pT816TrdZjw9P6ha7eMIeKM3iror6BXNtKFI38vzSLykjLOHCKuwUnAxdsph8exTzklpsgLcplJ2Pt4dEJbnEPRvsX+e1e20tX+pJcoNkR3psyvDPAfHoMsZgwERdmgdl7HbcwQd1UPItf7EICVGUAzksBCkwvDYq8E7FRPNV7EbJc4uIGiWSCY2Q0bcs23k16/K5O9+uEEgo3j6J/eooEzuhhkZMx+rETRAud9KLFr0OXpfwACwR4T18jBWF9LU6YxGM2bqiBKLsE8Gctj/XgXbZuQK7zgunHXE+xgqZgiHQlKlRsecJlK3Uf59O094RsEyI8yyJQd5kT/X8fIoMpLCzQqs08IH91lVvQws1ZzipDy/DyxYIBpQzeVQYQ/OCkIDxy4s7ew4hWlKCTSDW32sDUTwA6aej0U+jZk71eUSWhQlVX63br9YRhZ9n+mSI8Fkix3FHerzVBdsbDSlE88fP7vj9N96YIyOILRVjCcJRIZ1ixlxtRwpTTw/In42j6YLffvkV0/aGQjQYeVEnymdGhC/HhlHhSlWmGjbfiJ3UXxsxSyeANeccAlV76+7t6kME55uPC2AU16VYIwfWsj5T7cBSsxaEqmVlQiOgiLNRbR3wp1Q4azzCe1owFD5xt6SWds5zM17cnLlxgqonOHboKUIFDq8lUx/OXFDk8aBcqYJ4wYUau/3iH1ItZi2hDzOsMf5AliRMytaW+TUS/szyGcBGIIEWVEUPeuDoTGAVDtg4QV5TYpKcTmZneiYWXA0OziglknyLXZ2"
}