Terminal Management

Discover terminals and send trigger commands. List terminals requires terminals:read; sending triggers requires terminals:trigger.

GET/api/v1/{system}/listTerminalsšŸ”’ terminals:read

List terminals belonging to a branch. Returns terminal IDs, config IDs, online status, and assigned gateways. Tenant-isolated.

Auth: Bearer JWT

Request Body

FieldTypeRequiredDescription
branchIdlong (query)YesBranch user ID
excludeConfigIdlong (query)NoExclude a specific terminal (useful for the caller's own terminal)

Response Example

{
  "status": true,
  "data": [
    {
      "configId": 42,                        // long — pass to requestTerminal / capabilities
      "terminalId": "T-123",                 // string — opaque terminal id
      "accessId": "<branch access id>",      // string? — pass to requestTerminal
      "terminalTag": "Till 1",               // string? — operator label
      "laneTag": "A",                        // string? — physical lane id
      "posTag": "front-desk",                // string? — pos pairing hint
      "active": true,                        // bool  — admin hasn't disabled the terminal
      "activated": true,                     // bool  — merchant has completed pairing
      "online": true,                        // bool  — currently connected on WebSocket
      "currency": "NZD",                     // string
      "queueDestination": "/queue/terminal/42", // string — STOMP destination for cloud-ws
      "channels": {                          // map<string,bool> — enabled gateways
        "card": true,
        "wechat": true,
        "alipay": true,
        "unionPay": false,
        "centraPay": true
      }
    }
  ]
}
SandboxCalls go to https://payus.co.nz

Authentication

GET/api/v1/terminal/capabilities

Secret-free capability lookup for a terminal: which channels are enabled (wechat/alipay/unionPay/centraPay), the resolved gateway for each, and QR timing. Use it to offer only the channels the backend has enabled — never hardcode the channel list. Ownership-checked; returns no credentials (unlike /terminal/info, which is for the on-device app).

Auth: Bearer JWT

Request Body

FieldTypeRequiredDescription
idlong (query)YesTerminal config ID

Response Example

{
  "status": true,
  "data": {
    "configId": 123,
    "terminalId": "TERM-001",
    "channels": { "wechat": true, "alipay": true, "unionPay": false, "centraPay": true },
    "wechatGatewayConfig": { "id": 100, "gatewayName": "E-Payments", "testMode": false,
                             "supportsWechat": true, "supportsAlipay": true, "supportsUnionpay": false },
    "qrDisplayMs": 180000,
    "qrGraceMs": 210000,
    "paymentTimeoutMs": 360000,
    "configVersion": 3
  }
}
SandboxCalls go to https://payus.co.nz

Authentication

GET/api/v1/terminal/status

Lightweight liveness poll — far cheaper than /terminal/info and secret-free. Returns activation/active flags and a derived reason. Call it on app resume, cold start, and before starting a transaction; block the trading UI when active or activated is false. Ownership-checked.

Auth: Bearer JWT

Request Body

FieldTypeRequiredDescription
idlong (query)YesTerminal config ID

Response Example

{
  "status": true,
  "data": {
    "configId": 123,
    "terminalId": "TERM-001",
    "activated": true,
    "active": true,
    "reason": "ACTIVE"
  }
}
SandboxCalls go to https://payus.co.nz

Authentication

GET/api/v1/terminal/leafCert

LAN TLS leaf material (Q-022, Option B). Returns the terminal's per-terminal certificate + private key and the PayUs CA cert, so the on-device LAN server can run TLS and peers verify each other against the PayUs CA. Minted lazily on first fetch and persisted, so re-fetches are stable until rotation. Ownership-checked; the private key never leaves the owning tenant. (The matching per-branch LAN HMAC secret is delivered as lanSecret on the activation response and /terminal/info.)

Auth: Bearer JWT

Request Body

FieldTypeRequiredDescription
idlong (query)YesTerminal config ID

Response Example

{
  "status": true,
  "data": {
    "configId": 123,
    "terminalId": "TERM-001",
    "leafCertPem": "-----BEGIN CERTIFICATE-----\n…",
    "leafKeyPem": "-----BEGIN PRIVATE KEY-----\n…",
    "caCertPem": "-----BEGIN CERTIFICATE-----\n…",
    "notAfter": "2028-07-14T10:30:00Z"
  }
}
SandboxCalls go to https://payus.co.nz

Authentication

POST/api/v1/{system}/requestTerminalšŸ”’ terminals:trigger

Send a trigger command to a terminal via WebSocket. If the terminal is offline there is no durable queue — the command is NOT delivered and NOT replayed; requestStatus reports deliveryStatus TERMINAL_OFFLINE (vs SENT). Re-issue once the terminal is back online (listTerminals.online). See /docs/cloud-ws for the full hub ⇄ terminal flow (how the result comes back on your STOMP queue, or via requestStatus below).

Auth: Bearer JWT

Request Body

FieldTypeRequiredDescription
configIdlongYesTarget terminal config ID (from listTerminals)
terminalIdstringYesTerminal id (from listTerminals)
branchIdlongYesBranch id
accessIdstringYesBranch access id — same value sent in the activation payload; also returned by listTerminals
requestTypestringYesPAY | REFUND | CANCEL | PRINT
grandTotalstring (decimal)NoRequired for PAY and REFUND — the amount. Decimal string, 2 places, range 0.01–999999.99 (e.g. "12.50"). For REFUND omit for a full refund.
referenceIdstringNoPartner reference (PAY and REFUND). Strongly recommended on PAY: it is the idempotency key — a retry carrying the same referenceId returns the original request instead of charging twice.
tipAmount / feeAmount / donationAmount / discountstring (decimal)NoPAY only. Modifier portions of grandTotal, declaration-only (used to reconcile lineItems; NOT forwarded to the terminal and do not change the charge). Declare the tip here when it is included in grandTotal.
lineItemsLineItem[]NoPAY only, optional itemised basket (max 200). Same per-line shape as payNow: name, quantity (decimal string), unitPriceCents/lineTotalCents/taxCents (integer cents), sku?, category?. Reconciled strictly (±1c): sum(lineTotalCents) must equal grandTotal āˆ’ tip āˆ’ fee āˆ’ donation + discount; malformed or out-of-balance → HTTP 400 ERR_INVALID_LINE_ITEMS / ERR_LINE_ITEM_MISMATCH. Persisted and keyed to the sale by referenceId, so send one.
bodystringNoRequired for PRINT — the receipt text

Response Example

{
  "status": true,
  "data": {
    "id": 7,                        // numeric — poll requestStatus with this id
    "status": false,               // boolean — terminal has not reported a result yet
    "executed": false,             // boolean — set true once the terminal runs it
    "requestType": "PAY",
    "configId": 123,
    "referenceId": "ORD-42",
    "deliveryStatus": "SENT",      // SENT | TERMINAL_OFFLINE
    "requestInfo": null            // string — the terminal's result JSON, once available
  }
}
SandboxCalls go to https://payus.co.nz

Authentication

POST/api/v1/{system}/requestStatusšŸ”’ terminals:read

Poll for the result of a previously sent trigger. Equivalent to subscribing on STOMP and waiting for the COMMAND_RESULT frame — pick whichever fits your controller (see /docs/cloud-ws).

Auth: Bearer JWT

Request Body

FieldTypeRequiredDescription
idlongYesNumeric request id (data.id) returned by requestTerminal

Response Example

{
  "status": true,
  "data": {
    "id": 7,                        // numeric
    "status": true,                // boolean — terminal has reported a result
    "executed": true,              // boolean — the terminal ran the command
    "requestType": "PAY",
    "configId": 123,
    "referenceId": "ORD-42",
    "deliveryStatus": "SENT",      // SENT | TERMINAL_OFFLINE
    // requestInfo is a STRING holding the terminal's result JSON — parse it for the detail
    "requestInfo": "{\"paymentStatus\":\"SUCCESS\",\"tradeNo\":\"TRADE-123\",\"grandTotal\":\"12.50\",\"channel\":\"WECHAT\",\"currency\":\"NZD\"}"
  }
}
SandboxCalls go to https://payus.co.nz

Authentication