# BankCore 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 BankCore:

- HTTP API
- Serial API

Both methods use the same business commands and JSON contracts. Only the transport layer is different.

## 2. Integration Principles

- Use the same routes and JSON bodies for HTTP and Serial.
- Treat every response as a standard JSON response envelope.
- Use `pay_id` for idempotency and state recovery.
- For long-running operations, use `/check` polling.

## 3. HTTP Transport Profile

- Port: `8888`
- Content type: `application/json`
- If API key protection is enabled by deployment, send header `X-API-Key: <key>`.
- If API key is invalid/missing while protection is enabled, server returns `401 Unauthorized`.

Example base URL:

```text
http://127.0.0.1:8888
```

## 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: `<route>`
- With body: `<route>\n<json>`

Examples:

```text
/supported_operations
```

```text
/check
{"pay_id":"ORDER-1001","language":"en","no_print_data":false}
```

Response payload is always the standard JSON response envelope.

### 4.1 Serial Timeouts and Retry Guidance

Recommended values:

- Frame header read timeout: `3 s`
- 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 financial flow state via `/check` using the same `pay_id`.
- Do not blindly resend `/confirm` and `/cancel` on timeout.
- For `/sale` and `/refund`, prefer `/check`-based recovery before retrying.

## 5. API Routes

| Route                   | HTTP method | Body required | Body description            | Poll via `/check` |
|-------------------------|-------------|---------------|-----------------------------|-------------------|
| `/supported_operations` | GET or POST | No            | -                           | No                |
| `/terminals`            | POST        | No            | -                           | No                |
| `/sale`                 | POST        | Yes           | Financial operation request | Yes               |
| `/preauth`              | POST        | Yes           | Financial operation request | Yes               |
| `/confirm`              | POST        | Yes           | Financial operation request | Yes               |
| `/cancel`               | POST        | Yes           | Financial operation request | Yes               |
| `/refund`               | POST        | Yes           | Financial operation request | Yes               |
| `/xreport`              | POST        | Yes           | Report request              | Yes               |
| `/close-shift`          | POST        | Yes           | Report request              | Yes               |
| `/terminate`            | POST        | No            | -                           | No                |
| `/abort`                | POST        | Yes           | Abort request               | No                |
| `/check`                | POST        | Yes           | Status query request        | N/A               |

## 6. Common Response Envelope

Every route returns:

```json
{
    "status": "success",
    "data": {},
    "code": 0,
    "message": "OK"
}
```

Field format and behavior:

| Field     | JSON type    | Format                                                         | Presence rules                                                                         |
|-----------|--------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------|
| `status`  | string       | `success` or `error`                                           | Always present                                                                         |
| `data`    | object/null  | Route-specific payload                                         | May be omitted or `null` when there is no payload                                      |
| `code`    | integer/null | Error code (typically negative for business/processing errors) | Present for error responses; may be omitted or `null` for successful responses         |
| `message` | string/null  | Human-readable diagnostic text (UTF-8)                         | Usually present for error responses; may be omitted or `null` for successful responses |

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 Financial operation request body

Used by: `/sale`, `/preauth`, `/confirm`, `/cancel`, `/refund`

Money format:

- All monetary fields are integers in minor units.
- Do not send decimal separators or floating-point values.
- Examples for a 2-decimal currency: `1.00 -> 100`, `125.50 -> 12550`.
- For zero-decimal currencies, the value matches the whole amount.

| Field           | Type    | Required            | Description                                                        |
|-----------------|---------|---------------------|--------------------------------------------------------------------|
| `pay_id`        | string  | Recommended         | Integrator operation ID (idempotency key)                          |
| `terminal`      | long    | No                  | Terminal numeric ID (see terminal/merchant resolution rules below) |
| `merchant`      | long    | No                  | Merchant numeric ID (see terminal/merchant resolution rules below) |
| `amount`        | long    | Yes                 | Transaction amount in minor units                                  |
| `tips`          | long    | No                  | Tip amount in minor units                                          |
| `cashback`      | long    | No                  | Cashback amount in minor units                                     |
| `rrn`           | string  | Operation-dependent | Reference number for linked operations                             |
| `currency_name` | string  | Yes                 | Currency identifier/name                                           |
| `package_name`  | string  | No                  | Callback package identifier                                        |
| `doc_number`    | string  | No                  | External document number                                           |
| `headless`      | boolean | No                  | Headless mode flag                                                 |
| `no_printing`   | boolean | No                  | Disable printing                                                   |
| `txn_config`    | object  | No                  | Additional transaction options                                     |
| `language`      | string  | No                  | Response localization hint                                         |

Validation notes:

- `tips` and `cashback` cannot both be greater than zero.
- `currency_name` must be supported by deployment.

## 7.2 Report request body

Used by: `/xreport`, `/close-shift`

| Field          | Type    | Required | Description                                                        |
|----------------|---------|----------|--------------------------------------------------------------------|
| `pay_id`       | string  | No       | Integrator operation ID                                            |
| `terminal`     | long    | No       | Terminal numeric ID (see terminal/merchant resolution rules below) |
| `merchant`     | long    | No       | Merchant numeric ID (see terminal/merchant resolution rules below) |
| `package_name` | string  | No       | Callback package identifier                                        |
| `headless`     | boolean | No       | Headless mode flag                                                 |
| `no_printing`  | boolean | No       | Disable printing                                                   |
| `txn_config`   | object  | No       | Additional options                                                 |
| `language`     | string  | No       | Response localization hint                                         |

## 7.3 Terminal and merchant resolution rules

For routes that use transaction or report request bodies, `terminal` and `merchant` are resolved in this order:

1. Use `terminal` from the request if provided.
2. If not provided, use the currently selected terminal (session/default context).
3. If still not available, use the first configured terminal.
4. For `merchant`, use request value if provided.
5. If not provided, use the default merchant for the resolved terminal.

Important behavior:

- `merchant` is always resolved for the final terminal.
- If a requested or resolved terminal has no valid merchant, the request fails.
- If no terminal can be resolved, the request fails.
- If you send both fields, they must represent a valid pair in current configuration.

Integration recommendation:

- Use `/terminals` response as the source of valid `terminal` + `merchant` combinations.

## 7.4 Status query request body

Used by: `/check`

| Field           | Type    | Required | Description                                                              |
|-----------------|---------|----------|--------------------------------------------------------------------------|
| `pay_id`        | string  | Yes      | Operation ID to query                                                    |
| `language`      | string  | No       | Response localization hint                                               |
| `no_print_data` | boolean | No       | Omit `print_data` in `/check` response when transaction data is returned |

## 7.5 Abort request body

Used by: `/abort`

| Field           | Type    | Required | Description                                                              |
|-----------------|---------|----------|--------------------------------------------------------------------------|
| `pay_id`        | string  | Yes      | Operation ID to abort                                                    |
| `language`      | string  | No       | Response localization hint                                               |
| `no_print_data` | boolean | No       | Omit `print_data` in `/abort` response when transaction data is returned |

## 8. Route-Specific `data` Payloads

## 8.1 `/supported_operations`

```json
{
    "operations": [
        "abort",
        "terminate",
        "check",
        "terminals",
        "sale",
        "refund",
        "xreport",
        "close-shift"
    ]
}
```

Actual list depends on terminal configuration.

## 8.2 `/terminals`

```json
{
    "terminals": [
        {
            "terminal": 1,
            "terminalId": "12345678",
            "name": "Main",
            "merchant": 1,
            "merchantId": "M001",
            "merchantName": "Shop",
            "mcc": "5411",
            "fiscalId": "123456789"
        }
    ]
}
```

Terminal object fields:

- `terminal`: internal numeric terminal ID
- `terminalId`: external/acquirer terminal ID
- `name`: terminal name
- `merchant`: internal numeric merchant ID
- `merchantId`: external/acquirer merchant ID
- `merchantName`: merchant display name
- `mcc`: merchant category code
- `fiscalId`: fiscal identifier

Use these values as the authoritative source for valid routing pairs in requests.

## 8.3 `/check` response variants

`/check` always returns the standard JSON response envelope. The `data` field may be absent while operation is still in progress.

A final unsuccessful transaction may be returned as `status: "error"` with populated `data`.

### In progress (or not finalized yet)

```json
{
    "status": "success"
}
```

### Final approved

```json
{
    "status": "success",
    "data": {
        "txn_id": "TXN123",
        "status": "APPROVED",
        "card_num": "8600********1234",
        "rrn": "123456789012",
        "auth": "123456",
        "data": {},
        "print_data": {}
    }
}
```

### Final error

```json
{
    "status": "error",
    "data": {
        "txn_id": "TXN123",
        "status": "ERROR",
        "card_num": "8600********1234",
        "rrn": "123456789012",
        "error": "DECLINED",
        "data": {},
        "print_data": {}
    },
    "code": -20,
    "message": "Declined"
}
```

Returned transaction result statuses in `data.status`:

- `APPROVED`
- `ERROR`
- `REVERSED`

`IN_PROGRESS` is not returned as `data.status` by `/check`; while an operation is still running, `/check` returns `status: "success"`without
a transaction payload.

## 9. Integration Flows

## 9.1 Sale with polling

1. Send `/sale` with unique `pay_id`.
2. Receive initial response (often `status: "success"` without transaction payload).
3. Poll `/check` using same `pay_id`.
4. Stop polling only when `/check` returns a final transaction result in `data`:
    - `status: "success"` with `data.status = "APPROVED"`, or
    - `status: "error"` with `data.status = "ERROR"` or `"REVERSED"`.

Recommended polling interval: `1000-2000 ms`.

The same polling rule applies to `/preauth`, `/confirm`, `/cancel`, `/refund`, `/xreport`, and `/close-shift`.

## 9.2 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`.
3. Continue until final status is obtained.

## 9.3 Abort and terminate

- `/abort`: attempts to stop operation associated with `pay_id`
- `/terminate`: terminates active terminal session
- `/abort` does not require additional `/check` polling
- `/abort` may return final transaction data for approved operations (including final `data.status`)
- If `/abort` returns final transaction data, `no_print_data=true` omits `print_data`

## 10. Error Handling

`status=error` includes `code` and `message`.

Common examples:

- `-80`: operation not supported
- `-29`: invalid request parameters/body
- `-16`: original transaction not found
- `-15`: transaction not found
- `-47`: unsupported currency
- `-21`: cancelled by user
- `-20`: declined
- `-54`: card input timeout
- `-3`: generic send/processing error
- `-100`: critical version update required
- `-101`: application blocked

Recommendation: handle all unknown codes as non-retriable by default, then fallback to `/check` for state recovery when financial status is
uncertain.

## 11. HTTP Examples

## 11.1 Sale request

```bash
curl -X POST "http://127.0.0.1:8888/sale" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_KEY" \
  -d '{
    "pay_id":"ORDER-1001",
    "terminal":1,
    "merchant":1,
    "amount":12500,
    "currency_name":"UZS",
    "doc_number":"42",
    "headless":true,
    "no_printing":false,
    "language":"en"
  }'
```

Example response:

```json
{
    "status": "success"
}
```

## 11.2 Check request

```bash
curl -X POST "http://127.0.0.1:8888/check" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_KEY" \
  -d '{"pay_id":"ORDER-1001","language":"en","no_print_data":false}'
```

Example approved response:

```json
{
    "status": "success",
    "data": {
        "txn_id": "TXN123",
        "status": "APPROVED",
        "card_num": "8600********1234",
        "rrn": "123456789012",
        "auth": "123456",
        "data": {},
        "print_data": {}
    }
}
```

## 12. Serial Integration Checklist

1. Build payload as UTF-8 route/body string.
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.

