# Card Machine API Documentation

## Overview

The card machine API is a single-endpoint RPC-style gateway that bridges the CutPay cloud system with PAX A920 payment terminals running the `cutpay-pos-bridge-pax-A920` Android app.

**Endpoint**: `POST /api/cardmachine/payment` (alias: `POST /api/payment`)  
**Content-Type**: `application/json`  
**Base URL (Production)**: `https://icard.orderbuddy.tech/api/cardmachine/payment`

## Debug Log Viewer

To debug terminal delivery and callbacks in production:

- Web viewer: `https://icard.orderbuddy.tech/cardmachine/logs`
- JSON API: `https://icard.orderbuddy.tech/cardmachine/logs/api?date=YYYY-MM-DD&lines=200&filter=push`

Notes:
- Current log viewer route is temporarily open without auth for active incident debugging.
- Re-enable auth middleware after the incident is closed.

## Request Format

All requests share the same structure:

```json
{
  "route": "<route_name>",
  "params": { ... }
}
```

Authentication is via Bearer token in the `Authorization` header, or legacy `params.token` field.

---

## Routes

### `get_token` — Authenticate

Returns a 12-hour JWT for subsequent API calls.

**Params:**
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string | Yes | Account ID or user ID |
| `password` | string | Yes | Account password |
| `api_secret` | string | Yes | Shared API secret (`adcbba30-e793-4b80-baf3-0f855a89c8c6`) |

**Success Response:**
```json
{ "status": 200, "data": { "token": "<jwt_string>" } }
```

**Error Responses:**
- `{ "status": 108, "data": "Invalid API Secret" }`
- `{ "status": 108, "data": "ID is not recognized.." }`
- `{ "status": 108, "data": "Password is incorrect." }`

---

### `initiate_transaction` — Create Payment

Creates a new transaction and sends a push notification to the terminal.

**Auth**: Required (Bearer token)

**Params:**
| Field | Type | Required | Description |
|---|---|---|---|
| `amount` | int | Yes | Amount in pence/cents |
| `terminal` | string | Yes | Terminal ID |

**Success Response:**
```json
{ "status": 200, "data": <transaction_id> }
```

**Errors:**
- `{ "status": 111, "data": "Terminal is not in use" }` — terminal not found for account
- `{ "status": 402, ... }` — invalid/expired token

**Side Effect**: Sends Pushy push notification with payload:
```json
{ "terminal": "<id>", "transaction_id": "<id>", "amount": "<amount>" }
```

The API now sends `transaction_id` and `amount` as strings for Android compatibility.

---

### `update_transaction_status` — Update Status

Updates the `status` column of a transaction.

**Auth**: Required

**Params:**
| Field | Type | Required |
|---|---|---|
| `id` | int | Yes |
| `status` | string | Yes |

Common status values: `received`, `processing`, `completed`, `approved`, `failed`

**Response:** `{ "status": 200, "data": "Updated" }`

---

### `save_transaction_result` — Save Result JSON

Saves the libpositive result string and derives `payment_status`.

**Auth**: Required

**Params:**
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | int | Yes | Transaction ID |
| `result` | string | Yes | JSON string from libpositive |

**Derived `payment_status`:**
- Contains "approved" → `approved`
- Contains "declined/rejected/failed" → `declined`
- Contains "cancelled/canceled" → `cancelled`

**Response:** `{ "status": 200, "data": "Updated" }`

---

### `get_status_flow` — Get Terminal Status Events

Returns the terminal's status event history for a transaction.

**Auth**: Required

**Params:**
| Field | Type | Required |
|---|---|---|
| `id` | int | Yes |

**Response:**
```json
{ "status": 200, "data": ["Transaction started", "Pin Requested(Online)", "Transaction Approved"] }
```

---

### `update_status_flow` — Update Status Events

Replaces the terminal status flow array for a transaction.

**Auth**: Required

**Params:**
| Field | Type | Required |
|---|---|---|
| `id` | int | Yes |
| `status_flow` | array | Yes |

**Response:** `{ "status": 200, "data": "Updated" }`

---

## Terminal Management Routes

All terminal management routes are implemented and in production.

### `get_terminals` — List Terminals

**Auth**: Required

List all terminals for the authenticated account.

**Params:** None required

**Success Response:**
```json
{
  "status": 200,
  "data": [
    {
      "terminal_id": "T001",
      "terminal_name": "Front Desk",
      "advertisement_url": "https://...",
      "pin_required": "0"
    }
  ]
}
```

### `register_terminal` / `create_terminal` — Create Terminal

**Auth**: Required

**Params:**
| Field | Type | Required | Description |
|---|---|---|---|
| `terminal` | string | Yes | Terminal ID |
| `name` | string | No | Display name |
| `messaging_id` | string | No | Pushy device token |
| `advertisement_url` | string | No | WebView URL |

**Success Response:** `{ "status": 200, "data": "Terminal created" }`

**Errors:**
- `{ "status": 103, ... }` — terminal already exists or missing params

### `update_terminal` — Update Terminal

**Auth**: Required

Update a terminal's `messaging_id` (Pushy device token) for push notifications.

**Params:**
| Field | Type | Required | Description |
|---|---|---|---|
| `terminal` | string | Yes | Terminal ID |
| `messaging_id` | string | No | Pushy device token |
| `terminal_name` | string | No | Display name |
| `advertisement_url` | string | No | WebView URL |

**Success Response:** `{ "status": 200, "data": "Updated" }`

### `send_verify_terminal` — Verify Terminal

**Auth**: Required

Send a verification push to the terminal to confirm connectivity.

**Params:**
| Field | Type | Required | Description |
|---|---|---|---|
| `terminal` | string | Yes | Terminal ID |

**Push payload:** `{ "secret": "<VERIFICATION_SECRET>" }`

**Success Response:** `{ "status": 200, "data": "Verification sent" }`

---

## Error Codes

| Code | Meaning |
|---|---|
| 101 | Content-Type not application/json |
| 103 | Missing required parameters |
| 105 | Route name missing |
| 106 | Params not provided |
| 107 | Unknown route |
| 108 | Authentication failed |
| 111 | Terminal not found |
| 200 | Success |
| 402 | Token invalid or expired |
| 404 | Transaction not found |

---

## Database Schema

### `payment_account`
| Column | Type | Notes |
|---|---|---|
| `account_id` | bigint PK | Auto-increment |
| `user_id` | varchar(120) | Unique login ID |
| `password` | varchar(255) | Bcrypt hash |
| `date_created` | date | Nullable |
| `is_deleted` | boolean | Soft delete flag |

### `payment_terminal`
| Column | Type | Notes |
|---|---|---|
| `id` | bigint PK | Auto-increment |
| `account_id` | bigint | FK → payment_account |
| `terminal_id` | varchar(100) | Unique per account |
| `terminal_name` | varchar(200) | Display name |
| `advertisement_url` | varchar(500) | WebView URL |
| `messaging_id` | varchar(255) | Pushy device token |

### `payment_transaction`
| Column | Type | Notes |
|---|---|---|
| `id` | bigint PK | Auto-increment |
| `account_id` | bigint | Owner account |
| `terminal_id` | varchar(100) | Terminal that processed |
| `amount` | int | Amount in pence |
| `status` | varchar(100) | Lifecycle status |
| `payment_status` | varchar(50) | approved/declined/cancelled |
| `result` | text | libpositive JSON result |
| `terminal_status_flow` | longtext | JSON array of status events |
| `date_created` | date | Transaction date |
| `timestamp` | datetime | Created timestamp |
