Version 2.3 · Updated July 2026

PS-Connect Integration Docs

Connect your EPOS system to PAX payment terminals — run sales and refunds, watch transactions happen in real time, and reconcile everything with a clean REST + event-stream API.

ACTIVATED
Counter Payment
Waiting for Payment
NetworkConnected
ModeCounter Payment
StatusReady
Base URLcloud.psapp.uk

Introduction

This is the API reference for PS-Connect, the integration layer that lets EPOS systems talk directly to PAX payment terminals. Every endpoint below is documented with real request payloads and both success and failure responses, so you can wire up a sale, a refund, a batch report, or a live transaction feed without guessing at the shape of the data.

Getting started

This section explains how to get started using Connect over a secure HTTPS connection. Once this is all set up, you'll be ready to start working with the REST API.

Postman collection You can explore and test the endpoints using our Postman collection: Get Collection.

Messages over the HTTPS connection use JSON. Every message sent across the connection is documented below using a JSON schema that defines its structure. Each JSON schema is also provided in its raw form, so you can use it to validate messages while developing your integration.

Before you send a single request, the PAX terminal itself needs to be in the right state. PS-Connect can't process a transaction on a terminal that isn't ready for one.

Terminal status requirements

  1. Network connectivity — the terminal must be online via WiFi, SIM, or Ethernet
  2. Integration mode — the terminal must be in integration mode to accept API requests
  3. Counter Payment display — the screen must show the "Counter Payment" interface with the message "Waiting for Payment"
Transactions only process in Counter Payment mode If the terminal shows a different screen — main menu, settings, or a transaction already in progress — the API request will fail. Make sure the terminal isn't mid-transaction before starting a new one.

Terminal display reference

IndicatorStatus
Device statusActivated
NetworkConnected (WiFi / SIM / Ethernet)
ModeCounter Payment
Status messageWaiting for Payment

Troubleshooting terminal connectivity

IssueSolution
Terminal offlineCheck the WiFi/SIM/Ethernet connection and restart if necessary
Wrong display modeNavigate to "PS Connect" from the main menu or launcher
"Activated" not showingContact Paymentsave support to verify terminal activation
Terminal busyWait for the current transaction to finish, or cancel it

Terminal status indicators

StatusIndicatorAction required
OnlineActivatedReady to process transactions
StandbyMain menuNavigate to Counter Payment / Integration mode
OfflineNo networkCheck internet connection
BusyTransaction in progressWait, or cancel the current transaction
Pro tip Use the terminal's status display as a quick health check before firing off API calls. If it isn't showing Counter Payment, expect error -32075 (Terminal Unavailable).

Communication flow overview

PS-Connect follows a straightforward request/response pattern over REST. Here's the typical sequence, end to end.

  1. Generate an access token (POST) — exchange your API credentials for a bearer token
  2. Trigger an operation (POST) — send a transaction or report request with your auth headers; you get an immediate acknowledgement with a request_id, or an error
  3. Retrieve status (GET) — check overall status via /transaction/{requestID}/ or /report/{requestID}/
  4. Cancel an active transaction (POST) — via /cancel-active-transaction/
  5. Reprint a receipt (POST) — via /receipt-reprint/
  6. Optional: connect to the real-time stream/cloud/stream/devices/{device-uid}/events/

POS integration

Getting started over a secure HTTPS connection.

Requirements

  • Protocol: TLS 1.2+ required
  • Data format: JSON
  • Postman collection: available for testing endpoints

Base URLs

EnvironmentBase URL
UAT (Testing)https://paxuat.psapp.uk
Live (Production)https://cloud.psapp.uk

Every endpoint follows this pattern:

Pattern
https://{Base_URL}/api/v1/connect/pac/...

Authentication flow

  1. Get the access token — call the Get Token endpoint
  2. Use the access token — every REST call needs this header:
    Header
    Authorization: Bearer <ACCESS_TOKEN>
  3. Token expiration — access tokens typically expire after ~1 hour. Generate a new one if you hit a token-expiration error.

6.1Get token

POST/api/v1/connect/pac/token/

Use this endpoint to obtain your authentication token.

Request payload

Request
{
  "api_key": "88f98651-8138-4290-8ffd-1b2b8cff35b0",
  "software_house_id": "ZLDGIY0K",
  "device_uid": "54J5Q6W3"
}
FieldDescription
api_keyProvided by Paymentsave. Must be configurable in EPOS
software_house_idProvided by Paymentsave
device_uidProvided by Paymentsave. Must be configurable in EPOS

Success response

200 OK
{
  "status": "success",
  "code": 200,
  "data": {
    "access_token": "<ACCESS_TOKEN>"
  },
  "message": null
}

Failed response

401 Error
{
  "status": "error",
  "code": 401,
  "data": null,
  "message": "Invalid API credentials",
  "errors": {
    "message": "The provided api_key is invalid",
    "code": -32070
  }
}

6.2Run sale transaction

POST/api/v1/connect/pac/transaction/
Event: CONNECT_RUN_SALE

Initiates a sale (payment) transaction on the connected card terminal. Send this when you need the customer to pay a specific amount.

Request payload

Request
{
  "event": "CONNECT_RUN_SALE",
  "message": {
    "tid": "210202841806",
    "currency": "GBP",
    "amount": 1,
    "discount": 0,
    "gratuity": 0,
    "cashback": 0,
    "receipt_print": false
  }
}
FieldDescription
tidTerminal identifier — the payment terminal to use
eventMust be CONNECT_RUN_SALE
currencyISO 4217 currency code (e.g. GBP)
amountTransaction amount in smallest currency units, as an integer (e.g. 1000 = £10.00)
discountOptional discount, smallest currency units. Use 0 if none
cashbackOptional cashback, smallest currency units. Use 0 if none
gratuityOptional gratuity/tip, smallest currency units. Use 0 if none
receipt_printBoolean — whether the terminal should print a customer receipt

Success response

200 OK
{
  "status": "success",
  "code": 200,
  "data": {
    "status": "Sale request sent",
    "requestID": "c376bf33-b988-4555-b5fa-64428fbe5301"
  },
  "message": null
}

Failed response — terminal offline

400 Error
{
  "status": "error",
  "code": 400,
  "data": null,
  "message": null,
  "errors": {
    "message": "The device is currently offline or not in integration mode. Please check its internet connection and try again.",
    "code": -32075
  }
}
Watch for silent success If amount isn't sent as an integer, the API can still return 200 with "Sale request sent" — but the terminal never actually shows the transaction-taking page. Always validate that amount is an integer before sending.

6.3Run refund transaction

POST/api/v1/connect/pac/transaction/
Event: CONNECT_RUN_REFUND

Returns funds to a customer's card for a previous sale. Send this when the merchant wants to refund a specific past transaction.

Reference the original sale A refund must include the unique transaction identifier (UTI) of the original sale being refunded.

Request payload

Request
{
  "event": "CONNECT_RUN_REFUND",
  "message": {
    "tid": "210202841806",
    "currency": "GBP",
    "amount": 100,
    "refund_uti": "C3GHDDH-R3567GHF-45GFDDGBH-85FDDGHDF",
    "receipt_print": false
  }
}
FieldDescription
eventMust be CONNECT_RUN_REFUND
tidTerminal identifier for the refund
currencyISO 4217 currency code (e.g. GBP)
amountRefund amount in smallest currency unit (e.g. 1000 = £10.00)
refund_utiUTI of the original sale being refunded
receipt_printBoolean — print a receipt for the refund

Success response

200 OK
{
  "status": "success",
  "code": 200,
  "data": {
    "status": "Refund sale request sent",
    "requestID": "afdac53c-b791-40cb-a071-a9272f7c34e0"
  },
  "message": null
}

Failed response

400 Error
{
  "status": "error",
  "code": 400,
  "data": null,
  "message": null,
  "errors": {
    "message": "The device is currently offline or not in integration mode. Please check its internet connection and try again.",
    "code": -32075
  }
}

6.4Cancel active transaction

POST/api/v1/connect/pac/cancel-active-transaction/
Event: CONNECT_CANCEL_TRANSACTION

Aborts an in-progress transaction — for example, one still waiting for card insertion or authorization — due to user cancellation or timeout.

Request payload

Request
{
  "event": "CONNECT_CANCEL_TRANSACTION",
  "message": {
    "tid": "210202841806"
  }
}
FieldDescription
eventMust be CONNECT_CANCEL_TRANSACTION
tidTerminal whose current transaction should be cancelled
The response is an acknowledgement, not a guarantee The terminal will either succeed in cancelling, or — if it's too late, e.g. the transaction already completed — it may still go through. The final outcome is reflected in the termination of the original transaction's own event flow.

Success response

200 OK
{
  "status": "success",
  "code": 200,
  "data": {
    "status": "Cancel request sent",
    "requestID": "03a8d480-b58c-423f-aead-eac960146bf1"
  },
  "message": null
}

Failed response

400 Error
{
  "status": "error",
  "code": 400,
  "data": null,
  "message": null,
  "errors": {
    "message": "The device is currently offline or not in integration mode. Please check its internet connection and try again.",
    "code": -32075
  }
}

6.5Trigger batch report

POST/api/v1/connect/pac/report/

Triggers an X-Report or Z-Report on the terminal.

X-Report — a shift/interim report summarizing transaction totals (sales, refunds) without resetting them. Typically run at the end of a cashier's shift.

Z-Report — an end-of-day report totaling all transactions and generally resetting those totals. Typically run at close of business.

X-Report request payload

Request
{
  "report_type": "XREPORT",
  "tid": "210202841806",
  "print_receipt": "true"
}

Z-Report request payload

Request
{
  "report_type": "ZREPORT",
  "tid": "210202841806",
  "print_receipt": "true"
}
FieldDescription
tidTerminal identifier
report_typeEither XREPORT or ZREPORT

Success response

200 OK
{
  "status": "success",
  "code": 200,
  "data": {
    "status": "Batch request sent",
    "requestID": "c93e0a3a-d4f1-4049-88c5-4077b288b2c4"
  },
  "message": null
}

Failed response

400 Error
{
  "status": "error",
  "code": 400,
  "data": null,
  "message": null,
  "errors": {
    "message": "The device is currently offline or not in integration mode. Please check its internet connection and try again.",
    "code": -32075
  }
}

Failed response — missing required fields

400 Error
{
  "status": "error",
  "code": 400,
  "data": null,
  "message": null,
  "errors": { "error": "Missing required fields" }
}

6.6Retrieve batch report

GET/api/v1/connect/pac/report/{requestID}/

Retrieves a specific batch report using the requestID returned by Trigger Batch Report.

Success response

200 OK
{
  "status": "success",
  "code": 200,
  "data": {
    "id": 7140828,
    "tid": "210202841806",
    "mid": "2102028418",
    "report_type": "ZReport",
    "sale_count": 8,
    "sale_amount": "8.00",
    "refund_count": 5,
    "refund_amount": "511.00",
    "business_trading_name": "PAYMENTSAVE",
    "business_legal_name": "PAYMENTSAVE(UK) LIMITED",
    "created_at": "2026-07-02T12:45:50.069495",
    "updated_at": "2026-07-02T12:45:50.069506"
  },
  "message": null
}

Also includes completion_count, completion_amount, cashback_count, cashback_amount, gratuity_count, gratuity_amount, report_error, and epos_session_id.

Failed response — report not found

404 Error
{
  "status": "error",
  "code": 404,
  "data": null,
  "message": null,
  "errors": { "error": "Batch report not found" }
}

6.7Retrieve transaction details

PS-Connect offers two ways to monitor transaction status. The Event Stream is the primary, recommended method — the GET API is a fallback only.

Why the stream wins over polling
  • Persistent connection — once open, it stays open
  • No repeated authentication — the token is validated once
  • Real-time updates — instant notification of status changes
  • Lower server load — one connection instead of repeated polling
  • No manual token refresh — the stream handles it automatically

Primary method: Event Stream API

GEThttps://{Base_URL}/cloud/stream/devices/{device-uid}/events/

Maintains a persistent connection delivering real-time notifications about transaction and report lifecycle events for a specific terminal.

7 steps of a successful transaction

Transaction started GetCard screen Card type (CTLS/IC/SWIPE) Host approved Transaction approved SALE_COMD_RESULT Transaction finished
Step 1 · Transaction started
{
  "tid": "210202841806",
  "payload": {
    "event": "CONNECT_TERMINAL_NOTIFICATION",
    "session_id": "dbbc4b3e-85c5-453e-9bfe-0e2649e9af0c",
    "device_uid": "TAVK5VJ2",
    "message": "Transaction started",
    "received_ts": 1781259695405
  }
}
Step 2 · GetCard screen displayed Show "Please tap, insert, or swipe your card" on your POS screen when this event arrives.
Step 3 · Card type shown
{
  "tid": "210202841806",
  "payload": {
    "event": "CONNECT_TERMINAL_NOTIFICATION",
    "message": "Card type CTLS",
    "received_ts": 1781266029466
  }
}
  • CTLS — contactless tap
  • IC — chip insertion
  • SWIPE — magnetic stripe
Step 6 · SALE_COMD_RESULT (approved)
{
  "tid": "210202841806",
  "payload": {
    "event": "SALE_COMD_RESULT",
    "message": {
      "TransactionType": "SALE_AUTO",
      "UTI": "D453F4D9-8630-4FB6-8C69-8517DBFDEFC0",
      "Amount": 1,
      "Approved": true,
      "Cancelled": false,
      "Currency": "GBP",
      "TransactionDetails": {
        "ReceiptNumber": 142,
        "RRN": "616312186630",
        "ResponseCode": "00",
        "AuthCode": "012034",
        "CardType": "CTLS",
        "PAN": "************0081",
        "Scheme": "Visa"
      }
    }
  }
}

Declined transaction flow (6 steps)

Transaction started GetCard screen Host declined Transaction declined SALE_COMD_RESULT Transaction finished

Cancelled transaction flow (5 steps)

Transaction started GetCard screen SALE_COMD_RESULT (Cancelled: true) Transaction finished

Event types summary

EventDescription
CONNECT_TERMINAL_NOTIFICATIONStatus notifications — started, GetCard shown, card type, host approved/declined, transaction approved/declined, finished
SALE_COMD_RESULTFinal result of a sale transaction (approved, declined, or cancelled)
REFUND_COMD_RESULTFinal result of a refund transaction
BATCH_REPORT_RESULTResult of an X-Report or Z-Report

Authentication

Include the same JWT you received from Get Token, validated once when the stream connection opens:

Header
Authorization: Bearer <ACCESS_TOKEN>
StatusOutcomeDescription
401Missing/invalid tokenToken cannot be decoded or is malformed
403Access deniedValid credentials but software house ID not permitted for this device
404Not foundSome systems return this instead of 403 to avoid device enumeration
200SuccessEvent stream opened successfully
Key integration rule Use the Event Stream as your primary status-monitoring method. Avoid repeated GET polling during normal transaction processing — reach for the GET API only when the stream is temporarily unavailable.

When the stream disconnects

  1. Reconnect with backoff (2s, 4s, 8s… up to 30s max)
  2. For any in-flight request_id you care about, optionally reconcile via REST only if stream recovery is delayed:
    • GET /api/v1/connect/pac/transaction/{requestID}/
    • GET /api/v1/connect/pac/report/{requestID}/

Secondary method: GET API (fallback)

GET/api/v1/connect/pac/transaction/{requestID}/

Retrieves a single transaction's status. Only use this when the Event Stream is temporarily unavailable — it is not the preferred method.

Required field: requestID — the identifier generated when the transaction request was submitted.

Response — pending transaction

200 OK · PENDING
{
  "status": "success",
  "code": 200,
  "data": {
    "request_id": "ffb0bf95-d27e-4a49-9ace-7dbb708831a0",
    "transaction_type": "SALE_AUTO",
    "uti": "8598E885-926D-456B-9A2E-BA74BBF878F2",
    "amount": "0.01",
    "approved": false,
    "cancelled": false,
    "currency": "GBP",
    "terminal_id": "210202841806",
    "status": 5,
    "status_display": "PENDING",
    "created_at": "2026-06-03T13:31:35.187709"
  },
  "message": null
}

Success response — approved transaction

200 OK · APPROVED
{
  "status": "success",
  "code": 200,
  "data": {
    "request_id": "8bad16c3-4603-4ee7-8552-ecd446807ae6",
    "receipt_id": "125",
    "transaction_type": "SALE_AUTO",
    "pan": "************0081",
    "uti": "EDD06021-D506-4C8E-A5A1-C36A15C2A6C2",
    "amount": "0.01",
    "approved": true,
    "currency": "GBP",
    "card_type": "Visa",
    "response_code": "00",
    "auth_code": "074636",
    "rrn": "615412357993",
    "status": 1,
    "status_display": "APPROVED",
    "created_at": "2026-06-03T13:26:24.353211"
  },
  "message": null
}

Response — declined transaction

200 OK · DECLINED
{
  "status": "success",
  "code": 200,
  "data": {
    "request_id": "e8e60eb8-707d-4722-bb56-aad18e63530a",
    "error_text": "null, Do not honour",
    "pan": "************0043",
    "approved": false,
    "card_type": "CTLS",
    "response_code": "05",
    "status": 0,
    "status_display": "DECLINED",
    "created_at": "2026-06-03T13:21:33.082076"
  },
  "message": null
}

Response — cancelled transaction

200 OK · CANCELLED
{
  "status": "success",
  "code": 200,
  "data": {
    "request_id": "f63bad86-a668-4d39-9eef-d985c1dbf437",
    "receipt_id": "-1",
    "pan": "****************",
    "approved": false,
    "cancelled": true,
    "card_type": null,
    "status": 2,
    "status_display": "CANCELLED",
    "created_at": "2026-06-03T13:29:33.870991"
  },
  "message": null
}

6.8Re-print receipt

POST/api/v1/connect/pac/receipt-reprint/

Reprints a transaction receipt on the terminal — typically because the customer wants a duplicate or the original didn't print.

Request payload

Request
{
  "tid": "292837847383",
  "uti": "3783j37d-39wk3737289-dk38374j73h3"
}
FieldDescription
tidTerminal identifier
utiUTI of the transaction whose receipt should be reprinted
How the terminal handles this The terminal locates the transaction by its UTI (if still in batch memory) and prints a copy. If it can't find the transaction — the UTI isn't in memory, or the batch was already closed — it may respond with an error.

Success response

200 OK
{
  "status": "success",
  "code": 200,
  "data": {
    "status": "Receipt reprint request sent",
    "requestID": "b4ce0950-bc43-4d6b-b5ba-e87d7dd82820"
  },
  "message": null
}

7Error handling

Error response format

Failed Response
{
  "status": "error",
  "code": 400,
  "data": null,
  "message": null,
  "errors": {
    "message": "The device is currently offline or not in integration mode. Please check its internet connection and try again.",
    "code": -32075
  }
}

Error code reference

CodeMessageDescription
-32700Parse ErrorInvalid JSON was received by the server
-32600Invalid RequestThe JSON sent is not a valid Request object
-32071Invalid Param ValueOne or more parameter values are invalid or missing
-32072Request Not ProcessedThe received request has not been processed
-32073Response Not ProcessedThe received response has not been processed
-32074Request Timed OutThe Connect-to-EPOS request timed out; any response is no longer processed
-32075Terminal UnavailableThe request couldn't be processed because the terminal is unavailable

8Security best practices

Follow these guidelines to protect sensitive data and keep your integration secure.

1. Secure API key storage

  • Store API keys and credentials securely — never hard-code them
  • Use encrypted configuration files, environment variables, or a credential vault
  • Restrict access to these secrets

2. IP whitelisting

  • Restrict network access to PS-Connect by IP where possible
  • Configure firewalls or security groups so only trusted IPs — your POS terminals or store network — can reach the endpoint

3. Validate inputs and outputs

  • Always validate data sent to and received from PS-Connect
  • Check that responses are in the expected format and range
  • Verify amounts are correct and strings fall within expected length
  • Sanitize and validate data before including it in requests

4. Use TLS encryption

  • PS-Connect requires TLS by default — always use the secure HTTPS endpoint
  • Keep your client environment updated to support the latest TLS versions and ciphers
By adhering to these best practices, you help maintain the integrity of the payment process and protect sensitive information such as API keys and transaction details.
Paymentsave UK Ltd · support@paymentsave.co.uk · © 2026 Paymentsave UK Ltd. All Rights Reserved.
This documentation is protected under International and Federal Copyright Laws and Treaties.