> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.qfapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ECR Integration Technical Specification

> Integration protocol and encryption details for connecting POS systems with QFPay ECR.

<Note>
  **Supported Terminal Models**

  * **LANDI A8 / A8S** — All payment methods supported
  * **PAX A920** — QR code payments only
</Note>

***

## 1. POS-KEY

POS-KEY is a secret key used to encrypt transaction data. It is generated via the Haojin App.

Encryption is **enabled by default**. Merchants may toggle encryption on/off or regenerate the POS-KEY from the Merchant Portal (MMS). After changes, the POS device must refresh via the Haojin App.

### Refresh POS-KEY

Haojin App → **My → Settings → POS-Key → Generate**

### Check POS-KEY

Merchant Portal → **Settings → Device Settings → POS Key Mgmt**

***

## 2. Encryption

* Algorithm: **AES**
* Key: POS-KEY
* IV: `qfpay202306_hjsh`
* Output: Base64 encoded

***

## 3. Request Payload Format

| Attribute           | Mandatory | Type    | Description                                  |
| ------------------- | --------- | ------- | -------------------------------------------- |
| `amt`               | Yes       | Double  | Transaction amount (e.g. 10.1 = HKD \$10.10) |
| `func_type`         | Yes       | String  | Instruction code                             |
| `channel`           | Yes       | String  | Wallet/payment method                        |
| `out_trade_no`      | No        | String  | Merchant reference ID                        |
| `camera_id`         | No        | Integer | 0 = back camera (default), 1 = front camera  |
| `payment_timeout`   | No        | Integer | Payment timeout (seconds)                    |
| `wait_card_timeout` | No        | Integer | Card input timeout (default 120s)            |

***

### 3.1 Payment

<Note>
  **QR Mode**

  * MPM / CPM auto-selected based on last usage

  **Camera**

  * `0` back (default)
  * `1` front

  **Timeout**

  * Card: time to tap/swipe
  * Wallet/QR: time to confirm
  * PayMe max timeout: **120 seconds**

  **Scan Type**

  * `QRCODE_PAY`
  * `SCAN_PAY`

  **Return to Home**

  * `0` stay on result screen (default)
  * `1` return to home after transaction
</Note>

```json theme={null}
{
  "content": {
    "amt": 100,
    "camera_id": 0,
    "channel": "card_payment",
    "func_type": 1001,
    "moveToBack": 1,
    "out_trade_no": "456799999999",
    "wait_card_timeout": 120,
    "scan_type": "SCAN_PAY"
  },
  "digest": "76b9186077cdc2bc5d78ae921309811d"
}
```

***

### 3.2 Refund / Void

| Attribute           | Mandatory | Type    | Description              |
| ------------------- | --------- | ------- | ------------------------ |
| `orderId`           | Yes       | String  | QFPay transaction ID     |
| `refund_amount`     | No        | String  | Partial refund supported |
| `allow_modify_flag` | No        | Integer | 0 fixed, 1 allow change  |

<Note>
  For Visa, Mastercard, UnionPay Card, and Amex, same-day refunds must be **full amount**.
</Note>

```json theme={null}
{
  "content": {
    "allow_modify_flag": 1,
    "func_type": 1002,
    "orderId": "order_id",
    "refund_amount": "0.05",
    "moveToBack": 1
  },
  "digest": "9C8E9FB05C7C24B6CA04EBFA1263EF41"
}
```

***

### 3.3 Print Receipt

```json theme={null}
{
  "content": {"orderId": "12345678","func_type": 3001},
  "digest":"79fd145311d54d03e4e685d50f15dd7f"
}
```

***

### 3.4 Print Summary

```json theme={null}
{
  "content": {"func_type": 3002},
  "digest":"79fd145311d54d03e4e685d50f15dd7f"
}
```

***

### 3.5 Transaction Inquiry

```json theme={null}
{
  "content": {"orderId": "1234567890","func_type": 4001},
  "digest":"99CE8BF9C7304AC964522D10F51660B4"
}
```

***

### 3.6 Cancel Request

```json theme={null}
{
  "content": {"func_type": 5001},
  "digest": "99CE8BF9C7304AC964522D10F51660B4"
}
```

***

## 4. Signature Generation

```javascript theme={null}
// original payload
content={"amt":100,"channel":"card_payment","func_type":1001,"out_trade_no":"456799999999"}

// sort keys alphabetically
format_content={amt=100,channel='card_payment',func_type=1001,out_trade_no='456799999999'}

// generate digest
digest=md5(format_content + pos_key)
```

If encryption is enabled:

1. Encrypt `content` using AES
2. Generate digest from encrypted payload

***

## 5. Field Definitions

### func\_type

| Value | Description   |
| ----- | ------------- |
| 1001  | Payment       |
| 1002  | Refund        |
| 3001  | Print receipt |
| 3002  | Print summary |
| 4001  | Inquiry       |
| 5001  | Cancel        |

***

### channel (Payment Method)

| Value          | Description      |
| -------------- | ---------------- |
| card\_payment  | Credit card      |
| wx             | WeChat Pay       |
| alipay         | Alipay           |
| payme          | PayMe            |
| union          | UnionPay         |
| fps            | FPS              |
| octopus        | Octopus          |
| unionpay\_card | UnionPay Card    |
| amex\_card     | American Express |

***

## 6. Response Format

```json theme={null}
{"respcd":"6000","data":"{...}","respmsg":"OK","resperr":""}
```

### Response Codes

| Code | Meaning           |
| ---- | ----------------- |
| 6000 | Success           |
| 6001 | Cancelled         |
| 6002 | Error             |
| 4003 | Denied            |
| 5001 | Decryption failed |

***

## 7. Communication Methods

### USB

Connect POS to register via USB. Payload must be AES encrypted and parsed according to protocol.

### HTTP / HTTPS

* Default port: `9001`
* POST JSON payload
* AES encrypted

Endpoints:

| Operation     | Path                         |
| ------------- | ---------------------------- |
| Trade         | `/api/pos/trade`             |
| Refund        | `/api/pos/cancel`            |
| Print receipt | `/api/pos/print_receipt`     |
| Print summary | `/api/pos/transaction_info`  |
| Inquiry       | `/api/pos/query_transaction` |

<Note>
  For HTTPS setup, please refer to the [ECR Integration HTTPS](/integration/in-store/pos-api/ecr-https) documentation.
</Note>

### TCP

* Default port: `9002`
* Socket communication
* AES encrypted

***

## 8. USB Protocol Overview

Start indicator: `0x2f6e`\
Payload max: **65536 bytes**\
Recommended: ≤ **1024 bytes**

<Warning>
  `0x2f6e` represents the ASCII string "/n" — not a newline.
</Warning>

***

## 9. AES Encryption

* AES-128 CBC
* PKCS5 padding
* 16-byte key
* Required for request & response

***

## 10. Serial Port Settings

| Setting      | Value |
| ------------ | ----- |
| Baud rate    | 9600  |
| Stop bit     | 1     |
| Parity       | 0     |
| Data bits    | 8     |
| Flow control | Off   |

***

## 11. USB-Serial Chip Support

| Chip       | Supported |
| ---------- | --------- |
| PL2303 HXD | Yes       |
| CH340      | No        |
| FT232      | No        |

<Note>
  Chip support applies only to USB communication mode. HTTP / HTTPS and TCP integrations are unaffected.
</Note>
