# Antom DLL integration guide (Windows)

Electronic Data Capture (EDC) devices are widely used in various retail and service industries, especially in restaurants, supermarkets, and convenience stores. This guide introduces how to integrate an Antom DLL (dynamic link library) on Windows to quickly and securely handle payment needs, enhancing transaction efficiency and buyer experience.

# Prerequisites

-   Version equirements: Windows 7/10/11 (x86/x64).
-   Contact Antom business support to obtain the Antom SDK package.

> **Note**: The invocation of the Antom DLL SDK is currently available through Windows standard C++. If you are using cross-platform open-source libraries such as JNA, Flutter, Qt, or Electron for cross-language invocation, Antom cannot guarantee the stability of the cross-language context (including exceptions related to type conversion, memory management, etc.) or performance overhead. Should issues arise due to the open-source library itself, the integration party shall be responsible for troubleshooting and resolution. If you decide to use an open-source library, please ensure the following:
>
> -   Adopt the best practices for integrating the library.
> -   Upgrade to the latest stable version of the library.
> -   Customize and modify the library to resolve specific issues through community support or code branch checks.

# Integration steps

1.  Obtain the device
2.  Install _EasyCardK.exe_
3.  Install the DLL
4.  Initialize the DLL
5.  Send commands to the device
6.  Handle callbacks
7.  Clean up the DLL

## Step 1: Obtain the device

To obtain the device, please contact Antom business support for detailed information.

## Step 2: Install _EasyCardK.exe_

Please contact Antom business support for the installation instructions of _EasyCardK.exe_. After acquiring the equipment and completing the configuration, you can follow the following steps to complete the SDK integration.

## Step 3: Install the DLL

Add the library files (_.lib_) and header files (_.h_) from the provided SDK package to your ECR (Electronic Cash Register) project. These files contain Antom SDK's interface definitions required for the compilation process. Follow these steps to add the files in development environments like Visual Studio:

1.  Copy the header files into the source code directory of your ECR project, and reference the corresponding header file through the `#include` directive in the source file that needs to use the Antom SDK function.

```cpp
#include "AntomSdkInterface.h"
#include "IncCommon.h"
```

2.  Follow the steps below to add a static library to the project:

a. In the project properties, under **Linker** > **General** > **Additional Library Directories** > **Edit**, add the path of the _.lib_ file.

b. Click **Linker** > **Input** > **Additional Dependencies** > **Edit**, add the name of the _.lib_ file. For example, _antom-sdk.lib_.

3.  Place the provided _antom-sdk.dll_ in the same folder as the ECR executable. This is essential for loading the DLL at runtime, ensuring the program can correctly invoke the dynamic functions provided by Antom SDK. Ensure you place the correct version of the _.dll_ file based on the architecture of your ECR program:

-   For 32-bit ECR programs: Place _antom-sdk.dll_ from the **/antomSdk/libs/x86** directory.
-   For 64-bit ECR programs: Place _antom-sdk.dll_ from the **/antomSdk/libs/x64** directory.

After completing these steps, you can compile the ECR project as usual. At runtime, the program will automatically load the matching _antom-sdk.dll_ and invoke its functions.

## Step 4: Initialize the DLL

1.  Save the following configuration file as _config.yaml_ in the _conf_ folder that is located in the same directory as the executable _.exe_ file:

```cpp
loggers:
  is_upload: false
  is_prod: true
  max_cache_size: 1
  upload_interval: 1
  upload_url: https://imdap-sea.alipay.com/loggw/logUpload.do
  file:
    level: debug
    appenders:
      - type: file
        filename: "C:\\Users\\Administrator\\antom\\app_%Y-%m-%d.log"
        max_file_size: "10mb"
        max_files: "5"
        formatter: "[%Y-%m-%d %H:%M:%S.%e] [%l] file:[%@]  thread:[%P][%t] %v"
        clean_day: 7
apo:
  url: "https://imgs-sea-global.alipay.com/mgw.htm"
kicc:
  url: "http://127.0.0.1:8090"
  purchase_is_popup: false
  cashreceipt_is_popup: false
timeout:
  apo: 1500
  purchaseLowValue: 95000
  purchaseHighValue: 115000
  purchaseCancel: 85000
  cashReceipt: 65000
  cashReceiptCancel: 65000
  getLastTransaction: 5000
  purchaseCommandCancel: 30000
```

You can customize the following parameters of the configuration file based on your business needs:

| **Parameter name** | **Type** | **Description** |
| --- | --- | --- |
| _loggers.is\_upload_ | Boolean | Set whether logs are reported to the server. Valid values are: - `false`: Indicates that logs will be recorded locally and not submitted to the server. - `true`: Default value. Indicates that logs will be recorded and simultaneously uploaded to the server. |
| _loggers.is\_prod_ | Boolean | Distinguish the current runtime environment in event logs. Valid values are: - `false`: Indicates the non-production environment. - `true`: Indicates the production environment. |
| _loggers.max\_cache\_size_ | Integer | The maximum number of cached event logs. You can specify an integer value, and logs will only be uploaded once the cache reaches this threshold. |
| _loggers.upload\_interval_ | Integer | The interval (in seconds) at which event logs are uploaded. You can set it to an integer value. Regardless of the cache amount, logs will be uploaded at the set number of seconds. |
| _loggers.upload\_url_ | String | The base URL for uploading event logs. |
| _loggers.file.level_ | String | The logging level. The default value is `debug`, which indicates all logs of `debug` level and above (including `info`, `warn`, and `error`) will be recorded. |
| _loggers.file.appenders.type_ | String | The type of log. The fixed value is `file`. |
| _loggers.file.appenders__.filename_ | String | The storage path and file name format for log files. Log files will be named according to the `%Y-%m-%d` format to ensure a new log file is generated each day. |
| _loggers.file.appenders.max\_file\_size_ | String | The maximum size of a single log file (MB). The fixed value is `10mb`. When the file reaches the set maximum size, a new log file will be automatically created. |
| _loggers.file.appenders.max\_files_ | Integer | The maximum number of log files to retain. The fixed value is `5`, indicating that logs for the last five days will be kept. |
| _loggers.file.appenders.formatter_ | String | The output format for logs. The format includes timestamp, log level, filename, thread information, and the log message. |
| _loggers.file.appenders.clean\_day_ | Integer | The cleanup cycle for log files. The fixed value is `0`, indicating that logs are generated at 00:00 every day. |
| _apo.url_ | String | The base URL for the Antom Payment Orchestration (APO) API. The fixed value is `https://imgs-sea-global.alipay.com/mgw.htm`. |
| _kicc.url_ | String | The base URL for KICC API. |
| _kicc.purchase\_is\_popup_ | Boolean | Set whether to enable KICC's interactive popup for the **Purchase** command. Valid values: - `false`: Disables the popup. - `true`: Default value. Enables the popup. |
| _kicc.cashreceipt\_is\_popup_ | Boolean | Set whether to enable KICC's interactive popup for the **CashReceipt** command. Valid values: - `false`: Disables the popup. - `true`: Default value. Enables the popup. |
| _timeout__.apo_ | Integer | Set the timeout for APO APIs (in milliseconds). The default is `1500`. |
| _timeout.purchaseLowValue_ | Integer | Set the timeout (in milliseconds) for the KICC **Purchase** cammand when no signature is required. The default value is `95000`. > **Note**: If you need to customize the timeout setting for the **Purchase** command, ensure that it is not less than the default value. |
| _timeout.purchaseHighValue_ | Integer | Set the timeout (in milliseconds) for the KICC **Purchase** cammand when a signature is required. A signature is required when the payment amount exceeds 50,000 KRW, and the default value is `115000`. > **Note**: If you need to customize the timeout setting for the **Purchase** command, ensure that it is not less than the default value. |
| _timeout.purchaseCancel_ | Integer | Set the timeout (in milliseconds) for the KICC **PurchaseCancel** cammand. The default value is `85000`. |
| _timeout.cashReceipt_ | Integer | Set the timeout (in milliseconds) for the KICC **CashReceipt** cammand. The default value is `65000`. |
| _timeout.cashReceiptCancel_ | Integer | Set the timeout (in milliseconds) for the KICC **CashReceiptCancel** cammand. The default value is `65000`. |
| _timeout.getLastTransaction_ | Integer | Set the timeout (in milliseconds) for the KICC **GetLastTransaction** cammand. The default value is `5000`. |
| _timeout.purchaseCommandCancel_ | Integer | Set the timeout (in milliseconds) for the KICC **PurchaseCommandCancel** cammand. The default value is `30000`. |

2.  Use the following function to initialize the DLL and specify the required parameters:

-   _provider_: char\* type. Required. The device provider, fixed as `KICC`.
-   _merchantId_: char\* type. Required. The merchant ID.

```cpp
int initAntomSdk(const char* merchantId, const char* provider);
```

After initialization, the `initAntomSdk` function may return the following results:

-   `0`: Indicates the initialization is successful.
-   `-1`: Indicates the initialization failed. The DLL functions cannot be used. Restart the ECR program or refer to the logs to obtain the specific reason.

## Step 5: Send commands to the device

You can use either of the following methods to send commands to the device and retrieve execution results:

-   Use the `sendCommand` function (callback method) to send commands to the device and handle the command response through the `commandCallback` callback function.
-   Use the `sendCommandFile` function (file method) to send commands to the device. You need to manually monitor the changes to the response file to obtain the execution results of the commands.

#### Tab: sendCommand (callback method)

Use the `sendCommand` function to send commands to the KICC device. The method includes the following parameters:

| **Parameter name** | **Type** | **Required** | **Description** |
| --- | --- | --- | --- |
| _request_ | char\* | Yes | Request parameters. It includes the required parameter _commandName_, indicating the command name. Valid commands include: - **Purchase**: Initiate a payment. - **PurchaseCommandCancel**: Interrupt the payment process. - **PurchaseCancel**: Cancel a payment. - **CashReceipt**: Cash tax reporting. - **CashReceiptCancel**: Cancel cash tax reporting. - **GetLastTransaction**: Query the last successful transaction. |
| _commandCallback_ | function address | Yes | Callback address for executing device commands. |

Below is the declaration of the `sendCommand` function:

```cpp
int sendCommand(char* request, CommandCallback commandCallback);
```

After sending the device command, the `sendCommand` function may return one of the following results:

-   `0`: Indicates that the command was sent successfully.
-   `-1`: Indicates that the command sending failed. Please refer to the logs to obtain the specific reason.

#### Tab: sendCommandFile (file method)

You can send commands to the KICC device using the `sendCommandFile` function in file format, which includes the following parameters:

| **Parameter name** | **Type** | **Required** | **Required** |
| --- | --- | --- | --- |
| _requestFile_ | char\* | Yes | The file path. The content of the request file is in the JSON format with specific command parameters. Please refer to the example of the request file below to pass different command parameters. |
| _responseFile_ | char\* | Yes | The file path. The content of the response file is consistent with the command callback content. Please refer to [Step 6: Handle callbacks](#mLgix) to obtain the callback structure. |

Below is the declaration of the `sendCommandFile` function:

```cpp
int sendCommandFile(const char* requestFile, const char* responseFile);
```

After sending the device command, the `sendCommandFile` function may return one of the following results:

-   `0`: Indicates that the command was sent successfully.
-   `-1`: Indicates that the command sending failed. Please refer to the logs to obtain the specific reason.

The code below shows an example of the request file:

```json
{
  "requestId": "123456XXXX",
  "commandName": "Purchase",
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },
  "creditPayPlan": {
    "installmentNum": "0"
  },
  "paymentExpiryTime": "30",
  "acquirerInfo": {
    "acquirerTerminalId": "0788888",
    "acquirerRegistrationNo": "0216001234"
  }
}
```

The code below shows an example of the response file:

```json
{
  "data": {
    "acquirerInfo": {
      "acquirerApprovalNum": "99185628",
      "acquirerMerchantId": "00919895920",
      "acquirerMetaData": "eyJhY3F1aXJlckFwcHJvdmFsRGF0ZSI6IjI1MDcyMjE4NTYyODIiLCJhY3F1aXJlckFwcHJvdmFsTnVtIjoiOTkxODU2MjgiLCJhY3F1aXJlclRyYW5TZXJpYWxObyI6IjIyMTg1MzYyMzU1OSJ9",
      "acquirerName": "KICC",
      "acquirerRegistrationNo": "1168119948",
      "acquirerResultCode": "0000",
      "acquirerResultMessage": "",
      "acquirerTerminalId": "0788888",
      "acquirerTransactionId": "221853623559",
      "notice": " TEST퀵페이 선불충전",
      "signData": ""
    },
    "creditPayPlan": {
      "installmentNum": "00"
    },
    "paymentAmount": {
      "currency": "KRW",
      "value": "1234"
    },
    "paymentExpiryTime": "40",
    "paymentResultInfo": {
      "issuerCode": "050",
      "paymentMethodId": "451461*********"
    },
    "requestId": "550e8400-e29b-41d4-a716-446655441000",
    "result": {
      "resultCode": "SUCCESS",
      "resultMessage": "Success"
    },
    "taxAmount": {
      "currency": "KRW",
      "value": "112"
    },
    "tipAmount": {
      "currency": "KRW",
      "value": "109"
    }
  },
  "errorCode": "",
  "errorMessage": "",
  "resultCode": "APPROVED"
}
```

### Purchase

Use **Purchase** to initiate a payment, which includes the following parameters and sample codes:

#### Request parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | Merchant transaction number. | None |
| _commandName_ | Yes | Command name. | `Purchase` |
| _paymentAmount.value_ | Yes | Total payment amount. | None |
| _paymentAmount.currency_ | Yes | Currency of the payment. | `KRW` |
| _tipAmount.value_ | Yes | Service fee amount. | None |
| _tipAmount.currency_ | Yes | Currency of the service fee. | `KRW` |
| _creditPayPla__n.installmentNum_ | Yes | The number of installments. | None |
| _paymentExpiryTime_ | No | Payment timeout, which defaults to 30 seconds. | None |
| _acquirerInfo.acquirerTerminalId_ | Yes | ID of the terminal device. Cards and wallets usually use different ID. | None |
| _acquirerInfo.acquirerRegistrationNo_ | Yes | Merchant business license number. | None |

The following code shows a sample of the request message:

```json
{
  "requestId": "123456XXXX",
  "commandName": "Purchase",
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },
  "creditPayPlan": {
    "installmentNum": "0"
  },
  "paymentExpiryTime": "30",
  "acquirerInfo": {
    "acquirerTerminalId": "0788888",
    "acquirerRegistrationNo": "0216001234"
  }
}
```

#### Returned parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | Merchant transaction number. | None |
| _commandName_ | Yes | Command name. | `Purchase` |
| _paymentAmount.value_ | Yes | Total payment amount. | None |
| _paymentAmount.currency_ | Yes | Currency of the payment. | `KRW` |
| _taxAmount.value_ | Yes | Value-added tax amount. | None |
| _taxAmount.currency_ | Yes | Currency of the value-added tax. | `KRW` |
| _tipAmount.value_ | Yes | Service fee amount. | None |
| _tipAmount.currency_ | Yes | Currency of the service fee. | `KRW` |
| _creditPayPlan.installmentNum_ | Yes | The number of installments. | None |
| _result.resultCode_ | Yes | Payment result code. | None |
| _result.resultMessage_ | Yes | Payment result message. | None |
| _acquirerInfo.acquirerResultCode_ | No | Result code returned by the acquirer. | None |
| _acquirerInfo.acquirerResultMessage_ | No | Message description returned by the acquirer. | None |
| _acquirerInfo.acquirerTerminalId_ | Yes | ID of the terminal device. Cards and wallets usually use different ID. | None |
| _acquirerInfo.acquirerRegistrationNo_ | Yes | Merchant business license number. | None |
| _acquirerInfo.signData_ | No | Signature data. Only transmitted in signed transactions. | None |
| _acquirerInfo.notice_ | No | Transaction description. | `" 매입사제출테스트 거래임"` `"현금영수증 문의 Tel.126-1-1 http:\/\/hometax.go.kr"` `"전표:효력없음 userLoginId 000000000602"` |
| _acquirerInfo.acquirerTransactionId_ | Yes | Transaction serial number of the acquirer. | None |
| _acquirerInfo.acquirerMerchantId_ | Yes | The store's merchant ID on the acquirer end. | None |
| _acquirerInfo.acquirerName_ | Yes | Acquirer name. | `KICC` |
| _acquirerInfo.acquirerMetaData_ | Yes | Original data returned by the acquirer, which must be provided during the refund process. | None |
| _acquirerInfo.acquirerApprovalNum_ | Yes | Transaction approval number of KICC. | None |
| _paymentResultInfo.cardBin_ | No | Payment card BIN (first eight digits of the card). The card BIN information is required during card payment. | None |
| _paymentResultInfo.paymentMethodId_ | No | Identification number. Bar code is required in the wallet payment scenario. | None |
| _paymentResultInfo.issuerCode_ | Yes | Issuer code. See the attachment [📎79484bda-5fa3-4c69-b4ef-8cc7419668b1.xlsx](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/xlsx/cbd7d56f-fabd-49d4-adbc-e43a355a22dc.xlsx)for a full list. | None |
| _paymentResultInfo.funding_ | Yes | The card funding types include: Debit, Credit, and Prepaid. > **Note**: The value of this parameter is null when paying with international cards, wallets or Samsung Pay. | None |
| _paymentResultInfo.paymentMethodRegion_ | Yes | The region code that represents the country or region of the payment method. The value of this parameter is a 2-letter [ISO country code](https://www.iso.org/obp/ui/#search) or `GLOBAL`. | None |
| _paymentResultInfo.paymentMethodType_ | Yes | The payment method used by the buyer. | None |
| _extendInfo.AD1_ | No | Additional note 1 from the acquirer. | None |
| _extendInfo.AD2_ | No | Additional note 2 from the acquirer. | None |

The following code shows a sample of the response message:

```json
{
  "requestId": "123456XXXX",
  "commandName": "Purchase",
  "paymentAmount": {
    "value": "$TOTAL_AMOUNT",
    "currency": "KRW"
  },
  "taxAmount": {
    "value": "$TAX",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "$TIP",
    "currency": "KRW"
  },
  "creditPayPlan": {
    "installmentNum": "0"
  },
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "XXX"
  },
  "acquirerInfo": {
    "acquirerResultCode": "$RESULT_CODE",
    "acquirerResultMessage": "$RESULT_MSG",
    "acquirerTransactionId": "$TRAN_SERIALNO",
    "acquirerTerminalId": "$SHOP_TID",
    "acquirerRegistrationNo": "$SHOP_BIZ_NUM",
    "acquirerMerchantId": "$SHOP_TIDMERCHANT_NUM",
    "acquirerApprovalNum": "$APPROVAL_NUM",
    "acquirerName": "KICC",
    "notice": "               매입사제출테스트 거래임",
    "acquirerMetaData":"ImNyZWRpdFBheVBsYW4iOiB7CiAgICAiaW5zdGFsbG1lbnROdW0iOiAiMCIKICB9LAogICJyZXN1bHQiOiB7CiAgICAicmVzdWx0Q29kZSI6ICJTVUNDRVNTIiwKICAgICJyZXN1bHRNZXNzYWdlIjogIiIKICB9Cg=="
  },
  "paymentResultInfo": {
    "cardBin": "52364979",
    "paymentMethodId": "",
    "issuerCode": "$CARD_NAME",
    "funding": "DEBIT/CREDIT/PREPAID",
    "paymentMethodRegion": "KR",
    "paymentMethodType": "CARD/CONNECT_WALLET/SAMSUNGPAY"
  }
}
```

### PurchaseCommandCancel

After initiating a payment request, while waiting for the buyer to complete the payment via scan or card swipe, you can actively interrupt the payment process using the **PurchaseCommandCancel** command.

The **PurchaseCommandCancel** command is only used to submit an interruption request. The final payment result should be based on the result of the **Purchase** command. If the results of the **Purchase** command and the **PurchaseCommandCancel** command are inconsistent, the result of the **Purchase** command shall prevail. Specific scenarios are detailed in the table below:

| **Purchase** **command** | **PurchaseCommandCancel** **command** | **Final payment result** |
| --- | --- | --- |
| Success | Success | Payment success |
| Success | Failure | Payment success |
| Failure | Failure | Payment failure |
| Failure | Success | Payment failure |

> **Note**: The timing to trigger the payment interruption must be determined and controlled by you based on actual business scenarios.

#### Request parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | Merchant transaction number. | None |
| _commandName_ | Yes | Command name. | `PurchaseCommandCancel` |
| _purchaseRequestId_ | Yes | Merchant-side transaction number of the payment request to be interrupted. The value of this parameter must match the _requestId_ value passed in the **Purchase** command. | None |

The following code shows a sample of the request message:

```json
{
  "commandName":"PurchaseCommandCancel",
  "requestId":"550e8400-e29b-41d4-a716-446655441277",
  "purchaseRequestId":"550e8400-e29b-41d4-a716-446655441666"
}
```

#### Returned parameters

| **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| _data.purchaseRequestId_ | No | Merchant-side transaction number of the payment request to be interrupted. |
| _data.requestId_ | No | Merchant transaction number. |
| _data.resultInfo.resultCode_ | No | Result code of the payment interruption. |
| _data.resultInfo.resultMessage_ | No | Result message of the payment interruption. |
| _errorCode_ | Yes | Error code. Refer to [Error codes](#VPhLm) for details. This parameter is empty when the command executed successfully. |
| _errorMessage_ | Yes | Error message. This parameter is empty when the command executed successfully. |
| _resultCode_ | Yes | Result code of the command invocation. |

> **Note**: The criteria for a successful payment interruption is: _resultCode_ = `APPROVED` and _resultInfo.resultCode_ = `SUCCESS`. If the response does not meet this criteria, it is recommended to treat it as a failure.

#### Tab: Payment interruption success

The following code shows an sample response for a successful payment interruption:

```json
// Success
{
  "data":
  {
    "purchaseRequestId":"550e8400-e29b-41d4-a716-446655441666",
    "requestId":"550e8400-e29b-41d4-a716-446655441277",
    "resultInfo":
      {
        "resultCode":"SUCCESS", // Indicates that the PurchaseCommandCancel command was sent successfully
        "resultMessage":"Success"

      }
  },
  "errorCode":"",
  "errorMessage":"",
  "resultCode":"APPROVED"
}

```

#### Tab: Payment interruption failure

The following code shows the sample response that may be returned for a failed payment interruption scenario:

```json
// Failure
{
  "data":"",
  "errorCode":"PROCESS_FAIL",
  "errorMessage":"A general business failure occurred.",
  "resultCode":"DECLINED" // Indicates that the PurchaseCommandCancel command failed to send
}
or
{
  "data":"",
  "errorCode":"CommandParamError",
  "errorMessage":"Invalid interruption request: the specified requestId does not correspond to any payment currently in progress.",
  "resultCode":"COMMAND_ERROR"
}
```

### PurchaseCancel

Use **PurchaseCancel** to cancel payments or issue refunds. It includes the following parameters:

> **Note**: Card payments and Samsung Pay transactions support both full and partial refunds, while scan-to-pay transactions only support full refunds.

#### Request parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | Cancellation ID on the merchant side. The _requestId_ value is unique for each request. | None |
| _commandName_ | Yes | Command name. | `PurchaseCancel` |
| _paymentAmount.value_ | Yes | Total payment amount. | None |
| _paymentAmount.currency_ | Yes | Currency of the payment. | `KRW` |
| _tipAmount.value_ | Yes | Service fee amount. | None |
| _tipAmount.currency_ | Yes | Currency of the service fee. | `KRW` |
| _creditPayPlan.installmentNum_ | No | The number of installments. | None |
| _acquirerInfo.acquirerMetaData_ | Yes | Original data returned by the acquirer. Pass the value of _acquirerInfo.acquirerMetaData_ returned by the **Purchase** command to this parameter. | None |
| _acquirerInfo.acquirerTerminalId_ | No | ID of the terminal device. Cards and wallets usually use different ID. | None |
| _acquirerInfo.acquirerRegistrationNo_ | No | Merchant business license number. | None |

The following code shows a sample of the request message:

```json
{
  "requestId":"123456XXXX",
  "commandName": "PurchaseCancel",
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },
  "creditPayPlan": {
    "installmentNum":"0"
  },
  "acquirerInfo": {
    "acquirerTerminalId": "$SHOP_TID",
    "acquirerRegistrationNo": "$SHOP_BIZ_NUM",
    "acquirerMetaData":"ImNyZWRpdFBheVBsYW4iOiB7CiAgICAiaW5zdGFsbG1lbnROdW0iOiAiMCIKICB9LAogICJyZXN1bHQiOiB7CiAgICAicmVzdWx0Q29kZSI6ICJTVUNDRVNTIiwKICAgICJyZXN1bHRNZXNzYWdlIjogIiIKICB9Cg=="
  }
}
```

#### Returned parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | Cancellation ID on the merchant side. The _requestId_ value is unique for each request. | None |
| _commandName_ | Yes | Command name. | `PurchaseCancel` |
| _result.resultCode_ | Yes | Cancellation result. | None |
| _result.resultMessage_ | Yes | Cancellation result message. | None |
| _paymentAmount.value_ | Yes | Total payment amount. | None |
| _paymentAmount.currency_ | Yes | Currency of the payment. | `KRW` |
| _taxAmount.value_ | Yes | Value-added tax amount. | None |
| _taxAmount.currency_ | Yes | Currency of the value-added tax. | `KRW` |
| _tipAmount.value_ | Yes | Service fee amount. | None |
| _tipAmount.currency_ | Yes | Currency of the service fee. | `KRW` |
| _acquirerInfo.notice_ | No | Transaction description. | `" 매입사제출테스트 거래임"` `"현금영수증 문의 Tel.126-1-1 http:\/\/hometax.go.kr"` `"전표:효력없음 userLoginId 000000000602"` |
| _acquirerInfo.__acquirerResultCode_ | Yes | Result code returned by the acquirer. | None |
| _acquirerInfo.__acquirerResultMessage_ | No | Message description returned by the acquirer. | None |
| _acquirerInfo.acquirerTerminalId_ | No | ID of the terminal device. Cards and wallets usually use different ID. | None |
| _acquirerInfo.acquirerRegistrationNo_ | No | Merchant business license number. | None |
| _acquirerInfo.acquirerApprovalNum_ | Yes | Transaction approval number of KICC. | None |
| _acquirerInfo.acquirerMerchantId_ | Yes | The store's merchant ID on the acquirer end. | None |
| _acquirerInfo.acquirerTransactionId_ | Yes | Transaction serial number of the acquirer. | None |
| _acquirerInfo.acquirerMetaData_ | No | Original data returned by the acquirer. | None |
| _acquirerInfo.acquirerName_ | Yes | Acquirer name. | `KICC` |
| _extendInfo.AD1_ | No | Additional note 1 from the acquirer. | None |
| _extendInfo.AD2_ | No | Additional note 2 from the acquirer. | None |

The following code shows a sample of the response message:

```json
{
  "requestId":"123456XXXX",
  "commandName": "PurchaseCancel",
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "taxAmount": {
    "value": "9",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },
  "creditPayPlan": {
    "installmentNum":"0"
  },
  "result":{
    "resultCode":"SUCCESS",
    "resultMessage":""
  },
  "acquirerInfo": {
    "acquirerTerminalId": "$SHOP_TID",
    "acquirerRegistrationNo": "$SHOP_BIZ_NUM",
    "acquirerResultCode": "$RESULT_CODE",
    "acquirerResultMessage": "$RESULT_MSG",
    "acquirerTransactionId": "$TRAN_SERIALNO",
    "acquirerApprovalNum": "16263485",
    "acquirerMerchantId": "608525310521",
    "acquirerName": "KICC",
    "notice": "$NOTICE"
  }
}
```

### CashReceipt

Use **CashReceipt** to perform cash tax reporting, which includes the following parameters:

#### Request parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | Tax reporting ID on the merchant side. The _requestId_ value is unique for each request. | None |
| _commandName_ | Yes | Command name. | `CashReceipt` |
| _paymentAmount.value_ | Yes | Total payment amount. | None |
| _paymentAmount.currency_ | Yes | Currency of the payment. | `KRW` |
| _tipAmount.value_ | Yes | Service fee amount. | None |
| _tipAmount.currency_ | Yes | Currency of the service fee. | `KRW` |
| _buyerType_ | No | Type of the transaction entity for cash receipt. Valid values are: - `Individual`: An individual. The default value. - `Business`: Enterprise. | None |
| _reportType_ | No | Tax reporting method. Valid values are: - `auto`: Automatic approval of cash receipts. This is the default value. - `manual`: Manual approval of cash receipts (proactive issuance). | None |
| _acquirerInfo.acquirerTerminalId_ | No | ID of the terminal device. Cards and wallets usually use different ID. | None |
| _acquirerInfo.acquirerRegistrationNo_ | No | Merchant business license number. | None |

The following code shows a sample of the request message:

```json
{
  "requestId":"123456XXXX",
  "commandName": "CashReceipt",
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },
  "buyerType": "Individual/Business",
  "reportType": "auto/manual",
  "acquirerInfo": {
    "acquirerTerminalId": "0788888",
    "acquirerRegistrationNo": "0216001234"
  }
}
```

#### Returned parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | Tax reporting ID on the merchant side. The _requestId_ value is unique for each request. | None |
| _commandName_ | Yes | Command name. | `CashReceipt` |
| _paymentAmount.value_ | Yes | Total payment amount. | None |
| _paymentAmount.currency_ | Yes | Currency of the payment. | `KRW` |
| _taxAmount.value_ | Yes | Value-added tax amount. | None |
| _taxAmount.currency_ | Yes | Currency of the value-added tax. | `KRW` |
| _tipAmount.value_ | Yes | Service fee amount. | None |
| _tipAmount.currency_ | Yes | Currency of the service fee. | `KRW` |
| _acquirerInfo.notice_ | No | Transaction description. | `" 매입사제출테스트 거래임"` `"현금영수증 문의 Tel.126-1-1 http:\/\/hometax.go.kr"` `"전표:효력없음 userLoginId 000000000602"` |
| _result.resultCode_ | Yes | Processing result. | None |
| _result.resultMessage_ | Yes | Processing result message. | None |
| _cashIdentificationNo_ | Yes | Cash receipt identification number, which is usually a phone number. | `123456*******` |
| _institutionCode_ | Yes | Tax bureau code. | None |
| _acquirerInfo.__acquirerResultCode_ | Yes | Result code returned from the acquirer. | None |
| _acquirerInfo.__acquirerResultMessage_ | No | Message description returned by the acquirer. | None |
| _acquirerInfo.acquirerTransactionId_ | Yes | Transaction serial number of the acquirer. | None |
| _acquirerInfo.acquirerMetaData_ | Yes | Original data returned by the acquirer, which must be provided when cancelling the cash tax reporting. | None |
| _acquirerInfo.acquirerTerminalId_ | No | ID of the terminal device. Cards and wallets usually use different ID. | None |
| _acquirerInfo.acquirerRegistrationNo_ | No | Merchant business license number. | None |
| _acquirerInfo.acquirerApprovalNum_ | Yes | Transaction approval number of KICC. | None |
| _acquirerInfo.acquirerName_ | Yes | Acquirer name. | `KICC` |

The following code shows a sample of the response message:

```json
{
  "requestId": "123456XXXX",
  "commandName": "CashReceipt",
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "taxAmount": {
    "value": "9",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },

  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": ""
  },
  "cashIdentificationNo": "$CARD_NO",
  "institutionCode":"$ISSUER_CODE",
  "acquirerInfo": {
    "acquirerTerminalId": "$SHOP_TID",
    "acquirerRegistrationNo": "$SHOP_BIZ_NUM",
    "acquirerResultCode": "$RESULT_CODE",
    "acquirerResultMessage": "$RESULT_MSG",
    "acquirerTransactionId": "$TRAN_SERIALNO",
    "acquirerApprovalNum": "$APPROVAL_NUM",
    "acquirerName": "KICC",
    "notice": "$NOTICE",
    "acquirerMetaData":"ImNyZWRpdFBheVBsYW4iOiB7CiAgICAiaW5zdGFsbG1lbnROdW0iOiAiMCIKICB9LAogICJyZXN1bHQiOiB7CiAgICAicmVzdWx0Q29kZSI6ICJTVUNDRVNTIiwKICAgICJyZXN1bHRNZXNzYWdlIjogIiIKICB9Cg=="
  }
}
```

### CashReceiptCancel

Use **C****ashReceiptCancel** to cancel cash tax reporting, which includes the following parameters:

#### Request parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | ID of the merchant side to cancel the tax reporting. The _requestId_ value is unique for each request. | None |
| _commandName_ | Yes | Command name. | `CashReceiptCancel` |
| _paymentAmount.value_ | Yes | Total payment amount. | None |
| _paymentAmount.currency_ | Yes | Currency of the payment. | `KRW` |
| _tipAmount.value_ | Yes | Service fee amount. | None |
| _tipAmount.currency_ | Yes | Currency of the service fee. | `KRW` |
| _buyerType_ | No | Type of the transaction entity for cash receipt. Valid values are: - `Individual`: An individual. The default value. - `Business`: Enterprise. > **Note**: The value of this parameter must be the same as the value in the **cashReceipt** request. | None |
| _reportType_ | No | Tax reporting method. Valid values are: - `auto`: Automatic approval of cash receipts. The default value. - `manual`: Manual approval of cash receipts (proactive issuance). > **Note**: The value of this parameter must be the same as the value in the **cashReceipt** request. | None |
| _acquirerInfo.acquirerMetaData_ | Yes | Original data returned by the acquirer. Pass the value of _acquirerInfo.acquirerMetaData_ returned in the **CashReceipt** command to this parameter. | None |
| _acquirerInfo.acquirerTerminalId_ | No | ID of the terminal device. Cards and wallets usually use different ID. | None |
| _acquirerInfo.acquirerRegistrationNo_ | No | Merchant business license number. | None |

The following code shows a sample of the request message:

```json
{
  "requestId":"123456XXXX",
  "commandName": "CashReceiptCancel",
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },
  "reportType": "auto/manual",
  "paymentExpiryTime":"30",
  "acquirerInfo": {
    "acquirerTerminalId": "$SHOP_TID",
    "acquirerRegistrationNo": "$SHOP_BIZ_NUM",
    "acquirerMetaData":"ImNyZWRpdFBheVBsYW4iOiB7CiAgICAiaW5zdGFsbG1lbnROdW0iOiAiMCIKICB9LAogICJyZXN1bHQiOiB7CiAgICAicmVzdWx0Q29kZSI6ICJTVUNDRVNTIiwKICAgICJyZXN1bHRNZXNzYWdlIjogIiIKICB9Cg=="
  }
}
```

#### Returned parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _requestId_ | Yes | ID of the merchant side to cancel the tax reporting. The _requestId_ value is unique for each request. | None |
| _commandName_ | Yes | Command name. | `CashReceiptCancel` |
| _paymentAmount.value_ | Yes | Total payment amount. | None |
| _paymentAmount.currency_ | Yes | Currency of the payment. | `KRW` |
| _taxAmount.value_ | Yes | Value-added tax amount. | None |
| _taxAmount.currency_ | Yes | Currency of the value-added tax. | `KRW` |
| _tipAmount.value_ | Yes | Service fee amount. | None |
| _tipAmount.currency_ | Yes | Currency of the service fee. | `KRW` |
| _acquirerInfo.notice_ | No | Transaction description. | `" 매입사제출테스트 거래임"` `"현금영수증 문의 Tel.126-1-1 http:\/\/hometax.go.kr"` `"전표:효력없음 userLoginId 000000000602"` |
| _result.resultCode_ | Yes | Processing result. | None |
| _result.resultMessage_ | Yes | Processing result message. | None |
| _cashIdentificationNo_ | Yes | Cash receipt identification number, which is usually a phone number. | `123456*******` |
| _institutionCode_ | Yes | Tax bureau code. | None |
| _acquirerInfo.acquirerMetaData_ | No | Original data returned by the acquirer. | None |
| _acquirerInfo.acquirerTransactionId_ | Yes | Transaction serial number of the acquirer. | None |
| _acquirerInfo.__acquirerResultCode_ | Yes | Result code returned from the acquirer. | None |
| _acquirerInfo._ _acquirerResultMessage_ | No | Message description returned from the acquirer. | None |
| _acquirerInfo.acquirerTerminalId_ | No | ID of the terminal device. Cards and wallets usually use different ID. | None |
| _acquirerInfo.acquirerRegistrationNo_ | No | Merchant business license number. | None |
| _acquirerInfo.acquirerApprovalNum_ | Yes | Transaction approval number of KICC. | None |
| _acquirerInfo.acquirerName_ | Yes | Acquirer name. | `KICC` |

The following code shows a sample of the response message:

```json
{
  "requestId": "123123xxx",
  "commandName": "CashReceiptCancel",
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "taxAmount": {
    "value": "9",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": ""
  },
  "institutionCode":"$ISSUER_CODE",
  "cashIdentificationNo": "$CARD_NO",
  "acquirerInfo": {
    "acquirerTerminalId": "$SHOP_TID",
    "acquirerRegistrationNo": "$SHOP_BIZ_NUM",
    "acquirerResultCode": "$RESULT_CODE",
    "acquirerResultMessage": "$RESULT_MSG",
    "acquirerTransactionId": "$TRAN_SERIALNO",
    "acquirerApprovalNum": "$APPROVAL_NUM",
    "acquirerName": "KICC",
    "notice": "$NOTICE"
  }
}
```

### GetLastTransaction

Use **GetLastTransaction** to query the most recent transaction, which includes the following parameters:

#### Request parameters

| **Parameter name** | **Required** | **Description** | **Sample** |
| --- | --- | --- | --- |
| _commandName_ | Yes | Command name. | `GetLastTransaction` |

The following code shows a sample of the request message:

```json
{
  "commandName": "GetLastTransaction"
}
```

#### Returned parameters

The format of the returned parameters varies and depends on the type of _commandName_. The types include:

-   **Purchase**
-   **PurchaseCancel**
-   **CashReceipt**
-   **CashReceiptCancel**

The following sample code shows of a response format for **Purchase** type:

```json
{
  "requestId": "123456XXXX",
  "commandName":"Purchase"
  "paymentAmount": {
    "value": "104",
    "currency": "KRW"
  },
  "taxAmount": {
    "value": "9",
    "currency": "KRW"
  },
  "tipAmount": {
    "value": "0",
    "currency": "KRW"
  },
  "creditPayPlan": {
    "installmentNum": "0"
  },
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": ""
  },
  "acquirerInfo": {
    "acquirerTerminalId": "$SHOP_TID",
    "acquirerRegistrationNo": "$SHOP_BIZ_NUM",
    "acquirerResultCode": "$RESULT_CODE",
    "acquirerResultMessage": "$RESULT_MSG",
    "acquirerTransactionId": "$TRAN_SERIALNO",
    "acquirerMetaData":"ImNyZWRpdFBheVBsYW4iOiB7CiAgICAiaW5zdGFsbG1lbnROdW0iOiAiMCIKICB9LAogICJyZXN1bHQiOiB7CiAgICAicmVzdWx0Q29kZSI6ICJTVUNDRVNTIiwKICAgICJyZXN1bHRNZXNzYWdlIjogIiIKICB9Cg=="
  }
}
```

## Step 6: Handle callbacks

Use the `CommandResult` structure returned through the `handleCommandCallback` function to handle the result data when a device command execution is completed:

```cpp
void handleCommandCallback(CommandResult result)
{
    ...
}
```

`CommandResult` includes the following parameters:

| **Parameter name** | **Type** | **Description** |
| --- | --- | --- |
| _resultCode_ | enum | Command execution result. Valid values are: - `APPROVED`: Command executed successfully. - `COMMAND_ERROR`: Command error. - `DECLINED`: Transaction error or rejection (business error). |
| _szErrorCode_ | char\[\] | Error code. Refer to [Error codes](#VPhLm) for details. This parameter is empty when the command executed successfully. |
| _szErrorMessage_ | char\[\] | Error message. This parameter is empty when the command executed successfully. |
| _szData_ | char\[\] | JSON string of a successful response. Refer to the response format for each command in [Step 3. Send commands to the device](#PF4yE). This parameter is empty if the command failed. |

## Step 7: Clean up the DLL

To ensure efficient and orderly resource management, initialize the DLL once when the ECR program starts, and call the `cleanupAntomSdk` method provided by the DLL to release resources when the program exits. Below is an example of using `cleanupAntomSdk`:

```cpp
void cleanupAntomSdk();
```

# Error codes

The following error codes may be returned by the command error callback and business error callback:

| **Type** | **Code** | **Description** | **Further action** |
| --- | --- | --- | --- |
| Command error | CommandInvalidResponse | Returned result of the command is incorrect. | Use the [GetLastTransaction](#g6kD5) command to obtain the _requestId_ of the last successful transaction from the KICC side, and compare it with the _requestId_ of the current command. If both are consistent, it indicates that the transaction was successful; if the two _requestId_ are inconsistent, the transaction failed. If the issue is not resolved, please contact Antom Technical Support. |
| Command error | CommandResponseTimeout | The command was executed, but no response was returned. See the timeout setting in [Step 4. Initialize the DLL](#tcjgm) for more information. | Use the [GetLastTransaction](#g6kD5) command to obtain the _requestId_ of the last successful transaction from the KICC side, and compare it with the _requestId_ of the current command. If both are consistent, it indicates that the transaction was successful; if the two _requestId_ are inconsistent, the transaction failed. If the issue is not resolved, please contact Antom Technical Support. |
| Command error | CommandNotSupport | The command is not supported. | Please refer to [Step 5. Send commands to the device](#PF4yE) and input valid commands. |
| Command error | CommandDeviceBusy | The device is executing the command. | Wait for the previous command to respond and try again. |
| Command error | CommandParamError | Abnormal parameter. | Check the parameters of the input command. |
| Business error | REPEAT\_REQ\_REJECT | There is an existing order with the same _requestId_. | Please retry with a new _requestId_. |
| Business error | INVALID\_CONTRACT | Contract is invalid. | Please check the input _merchantId_ information. |
| Business error | ACCESS\_DENIED | Access is denied. | Contact KICC for detailed reasons and support. |
| Business error | PROCESS\_FAIL | A general business failure occurred. | Do not retry. Human intervention is usually needed. It is recommended that you contact Antom Technical Support to troubleshoot the issue. |
| Business error | PARAM\_ILLEGAL | The required parameters are not passed, or illegal parameters exist. For example, a non-numeric input, or the length and type of the parameter are wrong. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| Business error | ORDER\_STATUS\_INVALID | The order status is invalid. | Check the order status. |
| Business error | ORDER\_IS\_CANCELED | The transaction is canceled. | You cannot refund the transaction because it is canceled. |
| Business error | USER\_AMOUNT\_EXCEED\_LIMIT | The payment amount exceeds the user payment limit. | Create a new payment by using an amount less than or equal to the account's available balance, or contact Antom Technical Support. |
| Business error | USER\_BALANCE\_NOT\_ENOUGH | The payment cannot be completed because the user balance in the corresponding acquirer is not enough. | Please top up the account or choose other payment methods. |
| Business error | INVALID\_CARD\_NUMBER | The number of the card used for the transaction is invalid. | Check and verify whether the required request parameters of the current API are correctly passed and valid. |
| Business error | IDENTITY\_VERIFY\_FAILED | Identity verification timed out or the result couldn't be retrieved. | Please confirm your identification details and try again. |
| Business error | REFUND\_AMOUNT\_EXCEED | Cumulative refund amount exceeds the original payment amount. | Please check the refund amount you request and ensure that the total refund does not exceed the original payment amount. |
| Business error | UNKNOWN | Unknown scenarios. | Contact KICC for detailed reasons and support. |