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.
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.
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
- Network connectivity — the terminal must be online via WiFi, SIM, or Ethernet
- Integration mode — the terminal must be in integration mode to accept API requests
- Counter Payment display — the screen must show the "Counter Payment" interface with the message "Waiting for Payment"
Terminal display reference
| Indicator | Status |
|---|---|
| Device status | Activated |
| Network | Connected (WiFi / SIM / Ethernet) |
| Mode | Counter Payment |
| Status message | Waiting for Payment |
Troubleshooting terminal connectivity
| Issue | Solution |
|---|---|
| Terminal offline | Check the WiFi/SIM/Ethernet connection and restart if necessary |
| Wrong display mode | Navigate to "PS Connect" from the main menu or launcher |
| "Activated" not showing | Contact Paymentsave support to verify terminal activation |
| Terminal busy | Wait for the current transaction to finish, or cancel it |
Terminal status indicators
| Status | Indicator | Action required |
|---|---|---|
| Online | Activated | Ready to process transactions |
| Standby | Main menu | Navigate to Counter Payment / Integration mode |
| Offline | No network | Check internet connection |
| Busy | Transaction in progress | Wait, or cancel the current transaction |
-32075 (Terminal Unavailable).
Communication flow overview
PS-Connect follows a straightforward request/response pattern over REST. Here's the typical sequence, end to end.
- Generate an access token (
POST) — exchange your API credentials for a bearer token - Trigger an operation (
POST) — send a transaction or report request with your auth headers; you get an immediate acknowledgement with arequest_id, or an error - Retrieve status (
GET) — check overall status via/transaction/{requestID}/or/report/{requestID}/ - Cancel an active transaction (
POST) — via/cancel-active-transaction/ - Reprint a receipt (
POST) — via/receipt-reprint/ - 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
| Environment | Base URL |
|---|---|
| UAT (Testing) | https://paxuat.psapp.uk |
| Live (Production) | https://cloud.psapp.uk |
Every endpoint follows this pattern:
https://{Base_URL}/api/v1/connect/pac/...Authentication flow
- Get the access token — call the Get Token endpoint
- Use the access token — every REST call needs this header:
Header
Authorization: Bearer <ACCESS_TOKEN> - Token expiration — access tokens typically expire after ~1 hour. Generate a new one if you hit a token-expiration error.
6.1Get token
Use this endpoint to obtain your authentication token.
Request payload
{
"api_key": "88f98651-8138-4290-8ffd-1b2b8cff35b0",
"software_house_id": "ZLDGIY0K",
"device_uid": "54J5Q6W3"
}| Field | Description |
|---|---|
api_key | Provided by Paymentsave. Must be configurable in EPOS |
software_house_id | Provided by Paymentsave |
device_uid | Provided by Paymentsave. Must be configurable in EPOS |
Success response
{
"status": "success",
"code": 200,
"data": {
"access_token": "<ACCESS_TOKEN>"
},
"message": null
}Failed response
{
"status": "error",
"code": 401,
"data": null,
"message": "Invalid API credentials",
"errors": {
"message": "The provided api_key is invalid",
"code": -32070
}
}6.2Run sale transaction
Initiates a sale (payment) transaction on the connected card terminal. Send this when you need the customer to pay a specific amount.
Request payload
{
"event": "CONNECT_RUN_SALE",
"message": {
"tid": "210202841806",
"currency": "GBP",
"amount": 1,
"discount": 0,
"gratuity": 0,
"cashback": 0,
"receipt_print": false
}
}| Field | Description |
|---|---|
tid | Terminal identifier — the payment terminal to use |
event | Must be CONNECT_RUN_SALE |
currency | ISO 4217 currency code (e.g. GBP) |
amount | Transaction amount in smallest currency units, as an integer (e.g. 1000 = £10.00) |
discount | Optional discount, smallest currency units. Use 0 if none |
cashback | Optional cashback, smallest currency units. Use 0 if none |
gratuity | Optional gratuity/tip, smallest currency units. Use 0 if none |
receipt_print | Boolean — whether the terminal should print a customer receipt |
Success response
{
"status": "success",
"code": 200,
"data": {
"status": "Sale request sent",
"requestID": "c376bf33-b988-4555-b5fa-64428fbe5301"
},
"message": null
}Failed response — terminal offline
{
"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
}
}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
Returns funds to a customer's card for a previous sale. Send this when the merchant wants to refund a specific past transaction.
Request payload
{
"event": "CONNECT_RUN_REFUND",
"message": {
"tid": "210202841806",
"currency": "GBP",
"amount": 100,
"refund_uti": "C3GHDDH-R3567GHF-45GFDDGBH-85FDDGHDF",
"receipt_print": false
}
}| Field | Description |
|---|---|
event | Must be CONNECT_RUN_REFUND |
tid | Terminal identifier for the refund |
currency | ISO 4217 currency code (e.g. GBP) |
amount | Refund amount in smallest currency unit (e.g. 1000 = £10.00) |
refund_uti | UTI of the original sale being refunded |
receipt_print | Boolean — print a receipt for the refund |
Success response
{
"status": "success",
"code": 200,
"data": {
"status": "Refund sale request sent",
"requestID": "afdac53c-b791-40cb-a071-a9272f7c34e0"
},
"message": null
}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
}
}6.4Cancel active transaction
Aborts an in-progress transaction — for example, one still waiting for card insertion or authorization — due to user cancellation or timeout.
Request payload
{
"event": "CONNECT_CANCEL_TRANSACTION",
"message": {
"tid": "210202841806"
}
}| Field | Description |
|---|---|
event | Must be CONNECT_CANCEL_TRANSACTION |
tid | Terminal whose current transaction should be cancelled |
Success response
{
"status": "success",
"code": 200,
"data": {
"status": "Cancel request sent",
"requestID": "03a8d480-b58c-423f-aead-eac960146bf1"
},
"message": null
}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
}
}6.5Trigger batch report
Triggers an X-Report or Z-Report on the terminal.
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
{
"report_type": "XREPORT",
"tid": "210202841806",
"print_receipt": "true"
}Z-Report request payload
{
"report_type": "ZREPORT",
"tid": "210202841806",
"print_receipt": "true"
}| Field | Description |
|---|---|
tid | Terminal identifier |
report_type | Either XREPORT or ZREPORT |
Success response
{
"status": "success",
"code": 200,
"data": {
"status": "Batch request sent",
"requestID": "c93e0a3a-d4f1-4049-88c5-4077b288b2c4"
},
"message": null
}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
}
}Failed response — missing required fields
{
"status": "error",
"code": 400,
"data": null,
"message": null,
"errors": { "error": "Missing required fields" }
}6.6Retrieve batch report
Retrieves a specific batch report using the requestID returned by Trigger Batch Report.
Success response
{
"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
{
"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.
- 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
Maintains a persistent connection delivering real-time notifications about transaction and report lifecycle events for a specific terminal.
7 steps of a successful transaction
{
"tid": "210202841806",
"payload": {
"event": "CONNECT_TERMINAL_NOTIFICATION",
"session_id": "dbbc4b3e-85c5-453e-9bfe-0e2649e9af0c",
"device_uid": "TAVK5VJ2",
"message": "Transaction started",
"received_ts": 1781259695405
}
}{
"tid": "210202841806",
"payload": {
"event": "CONNECT_TERMINAL_NOTIFICATION",
"message": "Card type CTLS",
"received_ts": 1781266029466
}
}CTLS— contactless tapIC— chip insertionSWIPE— magnetic stripe
{
"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)
Cancelled transaction flow (5 steps)
Event types summary
| Event | Description |
|---|---|
CONNECT_TERMINAL_NOTIFICATION | Status notifications — started, GetCard shown, card type, host approved/declined, transaction approved/declined, finished |
SALE_COMD_RESULT | Final result of a sale transaction (approved, declined, or cancelled) |
REFUND_COMD_RESULT | Final result of a refund transaction |
BATCH_REPORT_RESULT | Result of an X-Report or Z-Report |
Authentication
Include the same JWT you received from Get Token, validated once when the stream connection opens:
Authorization: Bearer <ACCESS_TOKEN>| Status | Outcome | Description |
|---|---|---|
401 | Missing/invalid token | Token cannot be decoded or is malformed |
403 | Access denied | Valid credentials but software house ID not permitted for this device |
404 | Not found | Some systems return this instead of 403 to avoid device enumeration |
200 | Success | Event stream opened successfully |
When the stream disconnects
- Reconnect with backoff (2s, 4s, 8s… up to 30s max)
- For any in-flight
request_idyou 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)
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
{
"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
{
"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
{
"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
{
"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
Reprints a transaction receipt on the terminal — typically because the customer wants a duplicate or the original didn't print.
Request payload
{
"tid": "292837847383",
"uti": "3783j37d-39wk3737289-dk38374j73h3"
}| Field | Description |
|---|---|
tid | Terminal identifier |
uti | UTI of the transaction whose receipt should be reprinted |
Success response
{
"status": "success",
"code": 200,
"data": {
"status": "Receipt reprint request sent",
"requestID": "b4ce0950-bc43-4d6b-b5ba-e87d7dd82820"
},
"message": null
}7Error handling
Error response format
{
"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
| Code | Message | Description |
|---|---|---|
| -32700 | Parse Error | Invalid JSON was received by the server |
| -32600 | Invalid Request | The JSON sent is not a valid Request object |
| -32071 | Invalid Param Value | One or more parameter values are invalid or missing |
| -32072 | Request Not Processed | The received request has not been processed |
| -32073 | Response Not Processed | The received response has not been processed |
| -32074 | Request Timed Out | The Connect-to-EPOS request timed out; any response is no longer processed |
| -32075 | Terminal Unavailable | The 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