# PalmPay Integration Guide (HTTP + Serial)

Version: `v1`
Audience: third-party integrators

This is the single canonical integration document for both HTTP and Serial access.

## 1. Purpose

This guide describes two supported access methods to the PalmPay payment API:

- HTTP API
- Serial API

Both methods use the same business routes and JSON contracts. Only the transport layer is different.

The API is used to:

- detect available payment systems and supported operations
- start QR/Palm payment flow
- poll payment status
- perform cancel/refund/final confirm

## 2. Integration Principles

- Use the same routes and JSON bodies for HTTP and Serial.
- Always send `pay_system` exactly as configured (case-sensitive).
- Treat every response as the standard JSON response envelope.
- Use stable IDs (`pay_id`, `trans`) for polling and recovery.
- For long-running operations, use `/check` polling.

## 3. HTTP Transport Profile

- Port: `8887`
- Content type: `application/json`
- Methods: `POST` for all routes
- Authentication header: not required by this service layer

Example base URL:

```text
http://127.0.0.1:8887
```

## 4. Serial Transport Profile

- Encoding: UTF-8
- One request in flight per connection/session

Frame format:

```text
+----------------------+-------------------+-------------------+
| Length (4 bytes, BE) | Payload (N bytes) | CRC16 (2 bytes,BE)|
+----------------------+-------------------+-------------------+
```

Rules:

- `Length` is payload size in bytes, unsigned big-endian.
- `CRC16` is calculated over `Length || Payload`.
- CRC algorithm: CRC16-IBM (`0x8005`, initial `0x0000`).
- No extra transport ACK/NACK layer is defined.
- Frames with CRC mismatch must be discarded.

Request payload format:

- Without body: `:<port><route>`
- With body: `:<port><route>\n<json>`

`:<port>` is a mandatory prefix that selects the target service. For PalmPay use default `:8887`.

Examples:

```text
:8887/check_connection
```

```text
:8887/showqrcode
{"pay_id":"ORDER-1001","amount":12500,"currency":"USD","currency_name":"USD","pay_system":"miaPos"}
```

Response payload is always the standard JSON response envelope.

Authentication is not required on the serial channel.

### 4.1 Serial Timeouts and Retry Guidance

Recommended values:

- Frame payload read timeout: `5 s`
- Initial command response timeout: `30 s`
- `/check` polling interval: `1000-2000 ms`

Retry guidance:

- If client did not receive response frame, operation state is unknown.
- If CRC check fails on a received frame, treat response as not received.
- Recover payment state via `/check` using the same `pay_id` and `trans`.
- Do not blindly resend `/cancel`, `/refund`, and `/final_confirm` on timeout.
- For `/showqrcode`, prefer `/check`-based recovery before retrying.

## 5. API Routes

| Route               | HTTP method | Body required | Body description                           | Poll via `/check` |
|---------------------|-------------|---------------|--------------------------------------------|-------------------|
| `/check_connection` | POST        | No            | Discover enabled `pay_system` + operations | No                |
| `/showqrcode`       | POST        | Yes           | Start payment flow                         | Yes               |
| `/check`            | POST        | Yes           | Poll payment status                        | N/A               |
| `/cancel`           | POST        | Yes           | Cancel/refund flow                         | No                |
| `/refund`           | POST        | Yes           | Refund flow                                | No                |
| `/final_confirm`    | POST        | Yes           | Final confirmation/fiscal data             | No                |

Over Serial the same routes are addressed as `:8887<route>`.

## 6. Common Response Envelope

Every route returns:

```json
{
  "status": "success"
}
```

Field format and behavior:

| Field     | JSON type    | Format               | Presence rules                                                |
|-----------|--------------|----------------------|---------------------------------------------------------------|
| `status`  | string       | `success` or `error` | Always present                                                |
| `data`    | object/null  | Route-specific data  | Present only for some successful responses                    |
| `code`    | integer/null | Error code           | Typically `1` on `status=error`; usually omitted on success   |
| `message` | string/null  | Diagnostic message   | Usually present on `status=error`; usually omitted on success |

Parsing recommendation:

- Always parse by `status` first.
- Treat `data` as route-specific and optional.
- Do not rely on `message` text for business logic; use `code` and route context.

## 7. Request Models

## 7.1 `/check_connection` request body

No body.

## 7.2 `/showqrcode` request body

| Field           | Type    | Required | Description                                                                           |
|-----------------|---------|----------|---------------------------------------------------------------------------------------|
| `pay_id`        | string  | Yes      | Integrator payment/request ID                                                         |
| `rrn`           | string  | No       | External payment reference                                                            |
| `amount`        | long    | Yes      | Amount in minor units                                                                 |
| `currency`      | string  | Yes      | Currency code                                                                         |
| `currency_name` | string  | Yes      | Currency name                                                                         |
| `pay_system`    | string  | Yes      | Payment system selector (`iPay`, `miaPos`, `Palm`, `QRPh`, `Prozora`, `Uzum`, `QRAz`) |

## 7.3 `/check` request body

| Field        | Type   | Required | Description                   |
|--------------|--------|----------|-------------------------------|
| `pay_id`     | string | Yes      | Integrator payment/request ID |
| `trans`      | string | Yes      | Transaction ID                |
| `pay_system` | string | Yes      | Payment system selector       |

## 7.4 `/cancel` request body

| Field        | Type   | Required | Description                   |
|--------------|--------|----------|-------------------------------|
| `trans`      | string | Yes      | Transaction ID                |
| `pay_id`     | string | Yes      | Integrator payment/request ID |
| `rrn`        | string | Yes      | Retrieval reference number    |
| `amount`     | long   | Yes      | Amount in minor units         |
| `currency`   | string | Yes      | Currency code                 |
| `pay_system` | string | Yes      | Payment system selector       |

## 7.5 `/refund` request body

| Field        | Type   | Required | Description                   |
|--------------|--------|----------|-------------------------------|
| `trans`      | string | Yes      | Transaction ID                |
| `pay_id`     | string | Yes      | Integrator payment/request ID |
| `rrn`        | string | Yes      | Retrieval reference number    |
| `amount`     | long   | Yes      | Amount in minor units         |
| `currency`   | string | Yes      | Currency code                 |
| `pay_system` | string | Yes      | Payment system selector       |

## 7.6 `/final_confirm` request body

| Field        | Type   | Required | Description                   |
|--------------|--------|----------|-------------------------------|
| `pay_system` | string | Yes      | Payment system selector       |
| `trans`      | string | No       | Transaction ID                |
| `pay_id`     | string | No       | Integrator payment/request ID |
| `rrn`        | string | No       | Retrieval reference number    |
| `fiscal_id`  | string | No       | Fiscal identifier             |
| `fiscal_num` | string | No       | Fiscal number                 |
| `fiscal_url` | string | No       | Fiscal receipt URL            |
| `amount`     | long   | No       | Amount in minor units         |

## 8. Route-Specific `data` Payloads

## 8.1 `/check_connection`

```json
{
  "status": "success",
  "data": {
    "systems": [
      {
        "name": "iPay",
        "operations": ["showqrcode", "check", "cancel", "refund"]
      },
      {
        "name": "Uzum",
        "operations": ["showqrcode", "check", "refund", "final_confirm"]
      }
    ]
  }
}
```

`operations` is the authoritative source for currently available actions per system.
Actual list depends on terminal configuration.

## 8.2 `/showqrcode`

Success response may return either:

```json
{
  "status": "success"
}
```

or (for systems that return a transaction token immediately):

```json
{
  "status": "success",
  "data": {
    "trans": "123456"
  }
}
```

`data.trans` is optional in `/showqrcode` success responses.
If the selected payment system generates its own external transaction identifier, `/showqrcode` may return it in
`data.trans`. Save this value and use it in subsequent `/check`, `/cancel`, `/refund`, and `/final_confirm` requests.

## 8.3 `/check`

In progress:

```json
{
  "status": "success"
}
```

Final success:

```json
{
  "status": "success",
  "data": {
    "rrn": "654321"
  }
}
```

Final error:

```json
{
  "status": "error",
  "code": 1,
  "message": "ERROR_REASON"
}
```

## 8.4 `/cancel`

Typical successful payload:

```json
{
  "status": "success",
  "data": {
    "rrn": "123456789012"
  }
}
```

## 8.5 `/refund`

Typical successful payload:

```json
{
  "status": "success",
  "data": {
    "rrn": "123456789012"
  }
}
```

## 8.6 `/final_confirm`

Possible successful payloads:

```json
{
  "status": "success"
}
```

## 9. Integration Flows

## 9.1 Discover and start payment

1. Call `/check_connection`.
2. Select a `pay_system`.
3. Call `/showqrcode`.
4. Save your `pay_id` and system transaction identifier (`trans`) for polling.

## 9.2 Polling for result

1. Call `/check` with same `pay_id`, `trans`, `pay_system`.
2. If response is `status=success` without `data`, continue polling.
3. Stop when final `rrn` is returned or `status=error` is returned.

Recommended polling interval: `1000-2000 ms`.

## 9.3 Timeout / unknown result recovery

If client did not receive response (network issue, serial timeout, frame corruption):

1. Do not assume failure.
2. Query `/check` with same `pay_id` and `trans`.
3. Continue until final status is obtained.

## 9.4 Cancel or Refund and final confirm

- Use `/cancel` to run cancel/refund flow.
- Use `/refund` to run refund flow.
- Use `/final_confirm` to pass final confirmation or fiscal data.
- `/final_confirm` is an optional post-payment request and is not required to complete the base payment flow
  (`/showqrcode` + `/check`).
- Use `/check_connection` to discover configured systems and operations.

## 10. Error Handling

`status=error` responses include:

- `code`: typically `1`
- `message`: implementation/system error text

Recommendations:

- Parse by `status` first.
- Treat unknown `message` values as non-retriable by default.
- For payment state uncertainty, recover state via `/check`.

## 11. HTTP Examples

## 11.1 Check available systems

```bash
curl -X POST "http://127.0.0.1:8887/check_connection" \
  -H "Content-Type: application/json"
```

## 11.2 Start payment

```bash
curl -X POST "http://127.0.0.1:8887/showqrcode" \
  -H "Content-Type: application/json" \
  -d '{
    "pay_id":"ORDER-1001",
    "amount":12500,
    "currency":"MDL",
    "currency_name":"MDL",
    "pay_system":"miaPos"
  }'
```

## 11.3 Check payment status

```bash
curl -X POST "http://127.0.0.1:8887/check" \
  -H "Content-Type: application/json" \
  -d '{
    "pay_id":"ORDER-1001",
    "trans":"ORDER-1001",
    "pay_system":"miaPos"
  }'
```

## 11.4 Cancel payment example

```bash
curl -X POST "http://127.0.0.1:8887/cancel" \
  -H "Content-Type: application/json" \
  -d '{
    "trans":"123456",
    "pay_id":"ORDER-1001",
    "rrn":"123456789012",
    "amount":12500,
    "currency":"UAH",
    "pay_system":"iPay"
  }'
```

## 11.5 Final confirm example

```bash
curl -X POST "http://127.0.0.1:8887/final_confirm" \
  -H "Content-Type: application/json" \
  -d '{
    "pay_system":"Uzum",
    "pay_id":"ORDER-1001",
    "fiscal_url":"https://example.com/fiscal/receipt/123"
  }'
```

## 12. Serial Integration Checklist

1. Build payload as UTF-8 `:<port><route>` string, with `\n<json>` body when required.
2. Prefix payload length (`4-byte BE`).
3. Compute CRC16 over `Length || Payload`.
4. Append CRC (`2-byte BE`).
5. Send frame.
6. Read and validate response frame.
7. Parse response JSON as the standard response envelope.
