# Changelog

Welcome to the Changelog, your go-to resource for staying informed about the latest updates and improvements to our APIs.

## TBD, 2026 - **New Feature**

### Pay at Table: `/poslink/v1/tabs` endpoints

Added a new set of endpoints under `/poslink/v1/tabs` that let ePOS applications register tables (or open orders) with PosLink, list and inspect them, respond to terminal-initiated bill and payment requests, and close them once payment is complete.

**Key endpoints (ePOS-facing):**

- `POST /poslink/v1/tabs`: open a tab. Body: `{ "tab_id", "tab_name", "currency" }`. `tab_id` is an ePOS-chosen identifier; `tab_name` is the display label (e.g. `"Patio 3"`) shown on the terminal's open-tabs screen; `currency` is the ISO 4217 code all payments on the tab must use.
- `GET /poslink/v1/tabs`: paginated list of tabs. Query: `statuses=OPEN,PAYING,PAUSED,COMPLETED,CLOSED` (defaults to active statuses), `after`/`before` (opaque cursors), `limit`.
- `GET /poslink/v1/tabs/{tab_id}`: full tab detail including line items, payment requests, and the bill file id.
- `DELETE /poslink/v1/tabs/{tab_id}`: close a tab. PosLink also auto-closes tabs that have had no activity for 24 hours.

**Terminal-initiated event stream (Server-Sent Events):**

- `GET /poslink/v1/tabs/events`: SSE stream for the linked store. Notifies the ePOS of `SHOW_BILL_REQUEST`, `PAY_REQUEST`, `TAB_PAYMENT_STATUS_PROGRESS`, `TAB_PAYMENT_COMPLETED`, `TAB_PAUSED`, `TAB_RESUMED`, `TAB_COMPLETED`, `TAB_BILL_HIDDEN`, and connection state changes triggered by terminals against any open tab.

**ePOS response endpoints (in reply to events):**

- `POST /poslink/v1/tabs/{tab_id}/bill`: respond to a `SHOW_BILL_REQUEST` event with the bill total, plus an optional `print_model` or `tab_item_data` (`application/json`), or a pre-rendered bill image (`multipart/form-data`, maximum 200 KB per image and 220 KB per request; exceeding either returns `413` `PAYLOAD_TOO_LARGE` with code `BILL_IMAGE_TOO_LARGE`).
- `POST /poslink/v1/tabs/{tab_id}/errors`: reject a terminal-initiated request with an error code.

**Pay-at-Table response on existing payment endpoint:**

- `POST /poslink/v3/payment-requests` now accepts `tab_id`, `payment_type` (`FULL` or `SPLIT`) and `payment_method` (`CARD` or `CASH`) in the request body. Send them to settle a tab, fully or partially, in response to a `PAY_REQUEST` event; leave them out for regular payments. `payment_type` is required whenever `tab_id` is present. The payment is tagged against the tab and surfaces under `GET /poslink/v1/tabs/{tab_id}` as a `PaymentRequestSummary`.

**Store-level enablement:**

- `PUT /poslink/v1/stores/{store_id}/configs/PAT_ENABLED` accepts `{ "value": "true" }` to toggle PAT for the store. Store-wide capability flag; per-terminal opt-out is local to each terminal. Disabling is an entry-point gate only; in-progress sessions run to completion.

**Action Required**

No action required for existing integrations. Pay at Table is opt-in: partners that don't call the tab endpoints see no change.

For partners adopting PAT:

1. Enable PAT at the store level via `PUT /poslink/v1/stores/{store_id}/configs/PAT_ENABLED`.
2. Open a tab when a table is seated or an order is opened (`POST /poslink/v1/tabs`).
3. Subscribe to `/poslink/v1/tabs/events` to receive terminal-initiated bill and payment requests.
4. Respond to `SHOW_BILL_REQUEST` events with the bill, and to `PAY_REQUEST` events by creating a payment with `tab_id` and `payment_type`.
5. Close the tab when fully paid (`DELETE /poslink/v1/tabs/{tab_id}`).

See the [Pay at Table](/epos-sdk/poslink/android/pay-at-table) integration guide (Android) for the end-to-end flow and code samples. iOS and Windows guides ship alongside their respective SDK releases.

```admonition
icon: fas fa-info-circle
content: The Unified ePOS SDK v1.6.0 (Android, iOS, Windows) wraps these endpoints in a callback-based `PosLinkTabsApi`. Most partners should integrate via the SDK rather than calling the REST endpoints directly. The SDK handles the SSE stream lifecycle, reconnection with exponential backoff, and tab id ↔ terminal-side id mapping.
```

## Nov 11, 2026 - **Enhancement**

### More error responses documented

The reference now documents these error responses, with example bodies:

- `POST /poslink/v3/payment-requests`, `409`: `IDEMPOTENCY_KEY_REUSED` when the `Idempotency-Key` was already used with a different body, and `LOCAL_PAYMENT_REQUEST_MISMATCH` when `local_payment_request_id` or the `Idempotency-Key` belongs to another payment.
- `POST /poslink/v3/payment-requests`, `422`: `INVALID_TAB_REQUEST` when the request is not valid for a tab, for example `transaction_type` `REFUND` sent with a `tab_id`, with the rejected field in `invalid_params`; and `LOCAL_PAYMENT_REQUEST_INVALID` when `local_payment_request_id` is sent for a refund or a payment on a tab.
- `POST /poslink/v1/epos/register`, `409`: `STORE_CREDENTIALS_REMOVED` when the partner's credentials for the store have been removed.
- The `/poslink/v1/tabs/{tab_id}` endpoints, `404`: `TAB_NOT_FOUND` when no tab exists for the given `tab_id`.

The Errors section of the reference also lists every error code documented for each status, with its example.

**Action Required**

None.

## Nov 10, 2026 - **Bug Fix**

### V2 Refunds: No `202` Response

The API reference listed a `202` "Refund is being processed asynchronously" response for `POST /poslink/v2/refunds`. This endpoint never returns `202`. It has been removed from the reference.

A refund can still come back without a final result:

- `201` with `status` `PENDING`
- `400` with code `UNKNOWN`, which can mean a refund with the same `Idempotency-Key` is still being processed

There is no endpoint to fetch a refund later. In both cases, repeat the same request with the same `Idempotency-Key` and body. The repeated request returns the stored refund instead of creating a new one.

**Action Required**

Always send an `Idempotency-Key` on `POST /poslink/v2/refunds`, and handle `PENDING` and `400 UNKNOWN` by repeating the request with the same key. Without a key, every request creates a new refund.

No API behaviour changed. This entry corrects the documentation only.

See [Refunds](/apis/poslink/apis#refunds) in the API reference and [Make a refund](/poslink/develop/make-refund).

## Nov 9, 2026 - **New Feature**

### Terminal Names: `GET /poslink/v2/stores/{store_id}/terminals`

Added a new version of the terminal listing that returns each terminal's actual name, and its device model in a separate field.

**What changes from V1:**

- `terminal_name` now returns the name of the terminal, which can contain emojis. In V1 this field returns the device model.
- `device_model` is a new field that returns the device model, for example `PAX_A77`.

**Action Required**

No action required for existing integrations: `GET /poslink/v1/stores/{store_id}/terminals` does not change. To show terminal names, move to V2. If you read the device model from `terminal_name`, read `device_model` instead.

## Sep 3, 2026 - **Bug Fix**

### V2 Refunds: Which Identifier Goes in `transaction_id`

The May 21, 2026 deprecation notice below was misleading about `POST /poslink/v2/refunds`. It read as though V2 takes a different identifier from V1. It does not.

The request field is named `transaction_id`, but the value it expects is the **`gateway_payment_id`** of the original payment, the same identifier V1 refunds took. The field name and the identifier name simply differ.

Send the `gateway_payment_id` of the original payment, delivered when that payment completes on its status stream ([`GET /poslink/v3/payment-requests/{payment-request-id}`](/apis/poslink/apis#payment-requests)):

```json
{
  "transaction_id": "39e3bacdd5d38d9ce611cf88afbcc86df829a9a5641880b3",
  "amount": 1500
}
```

Do **not** send the deprecated `transaction_id` from the V1 payment request response. Despite the matching field name it is a different identifier and the refund will fail with `404 TRANSACTION_NOT_FOUND`.

**Action Required**

None if your refunds are working today. If you see `404 TRANSACTION_NOT_FOUND`, check you are sending the `gateway_payment_id` of the original payment.

No API behaviour changed. This entry corrects the documentation only.

See [Refunds](/apis/poslink/apis#refunds) in the API reference and [Make a refund](/poslink/develop/make-refund).

## Aug 17, 2026 - **New Feature**

### Receipt Text Endpoint

Added `GET /poslink/v3/payment-requests/{payment-request-id}/receipt-text`, which returns a JSON response with a `receipt_text` field containing the plain-text receipt for a `SUCCESSFUL` payment request or refund.

**What the receipt includes:**

- Store name and address
- UTC transaction date/time
- Amount, tip, and total
- Card details, AID, MID, TID, approval code, response code, entry mode, verification method, card type, and card issuing country
- DCC details, where applicable
- Receipt references (gateway reference and merchant reference)

Optional fields are omitted when absent, so no blank labels are printed.

**Required scopes (one of the following):**

- `payment_requests/id`
- `default_access` (deprecated; included for backward compatibility with existing integrations)

**Action Required**

No action required for existing integrations. The endpoint is additive and opt-in: call it after a payment request reaches `SUCCESSFUL` if you want a ready-to-print text receipt instead of composing one from the payment metadata yourself.

## Jul 22, 2026 - **Enhancement**

### V3 Payment Request Stream

`GET /poslink/v3/payment-requests/{payment-request-id}` supersedes the V2 endpoint for Transaction Updates over Server-Sent Events. Unlike V2, it also streams refunds and returns the raw `status_reason` rather than collapsing unrecognised reasons to `EXPIRED`.

**New `status_reason` values on V3** (all reported as `EXPIRED` on V2):

- `TERMINAL_UNREACHABLE`: the terminal could not be reached to deliver the push notification
- `NOTIFICATION_EXPIRED`: the push notification expired before the terminal received it
- `SUPERSEDED_BY_NEW_TRANSACTION`: a newer payment request was started on the same terminal
- `TRANSACTION_ALREADY_IN_PROGRESS`: the terminal is already processing a transaction
- `UNSUPPORTED_CURRENCY`: the terminal does not support the requested currency
- `FEATURE_NOT_ACTIVATED_UNREFERENCED_REFUNDS`: unreferenced refunds are not activated for the terminal

**Action Required**

1. Move Transaction Update subscriptions from `GET /poslink/v2/payment-requests/{payment-request-id}` to V3.
2. Handle the `status_reason` values above, and keep tolerating unrecognised values, more may be added over time.

Cancelling a payment request is unaffected and remains on `PATCH /poslink/v2/payment-requests/{payment-request-id}`.

---

## Jul 22, 2026 - **Breaking Change**

### V1 Payment Requests List and V1 Refunds Removed

`GET /poslink/v1/payment-requests` and `POST /poslink/v1/refunds` have been removed.

**Action Required**

1. Move from `GET /poslink/v1/payment-requests` to [`GET /poslink/v2/payment-requests`](/apis/poslink/apis#payment-requests), which also returns refunds alongside payments and adds `type` and date-range filters.
2. Move from `POST /poslink/v1/refunds` to `POST /poslink/v2/refunds`, deprecated since May 21, 2026 (see below) and now fully removed.

---

## May 21, 2026 - **Deprecation**

### V1 Refunds Endpoint Deprecated

The V1 refunds endpoint `POST /poslink/v1/refunds` is now deprecated in favour of the new [V2 refunds endpoint](/apis/poslink/apis#refunds) (`POST /poslink/v2/refunds`).

**Action Required**

Migrate your refund integrations from V1 to V2:

1. Switch from `POST /poslink/v1/refunds` to `POST /poslink/v2/refunds`.
2. Move the original payment's `gateway_payment_id` into the V2 request field named `transaction_id`. The field name differs from V1, the identifier you send does not.
3. Update your response handling for the richer V2 payload (`issuer_result`, `dcc`, and the `REFUND`/`REVERSAL` transaction types).
4. Do **not** send `terminal_id` in the request body unless you authenticate with client credentials (M2M). V1 had no such field; V2 added it, and sending it with a user token is rejected with `403 FORBIDDEN` on every attempt. POSLink refunds are referenced online refunds - the terminal is derived from the original payment, so omitting `terminal_id` loses nothing.

```admonition
icon: fas fa-exclamation-triangle
content: |
    **Corrected Sep 3, 2026.** Step 2 previously read "Identify the original transaction using `transaction_id` instead of `gateway_payment_id`", which wrongly implied V2 takes a different identifier. V2 takes the same `gateway_payment_id` as V1, in a field named `transaction_id`. See the Sep 3, 2026 correction above.
```

```admonition
icon: fas fa-exclamation-triangle
content: The V1 refunds endpoint remains available during a transition period but will be removed in a future release. Migrate to V2 as soon as possible to avoid disruption.
```

## May 21, 2026 - **New Feature**

### V2 Refunds Endpoint

Added `POST /poslink/v2/refunds` for refunding a previously processed transaction. The original payment is identified by its `gateway_payment_id`, sent in a request field named `transaction_id`, and the response carries richer settlement data than V1.

**Key Features:**
- Refund by the original payment's `gateway_payment_id`, with optional partial amounts via the `amount` field (smallest currency unit)
- Optional `Idempotency-Key` header to safely retry requests without creating duplicate refunds
- Response includes the issuer authorisation result (`issuer_result`) and Dynamic Currency Conversion details (`dcc`) when applicable
- Supports both `REFUND` and `REVERSAL` transaction types

See [Refunds](/apis/poslink/apis#refunds) in the API reference.

## Nov 14, 2025 - **Added** Real-Time Payment Status API with SSE Support

Added new API method [GET payment-request V2](/apis/poslink/apis#payment-requests)
, which provides real-time updates of payment status over the Server-Sent Events (SSE) protocol.

## June 18, 2025 - **Deprecation**

### Deprecation of source_reference_id in Favor of merchant_reference in POSLink API Responses

```admonition
icon: fas fa-exclamation-triangle
content: Starting June 19, 2025, the field `source_reference_id` will be deprecated and replaced by `merchant_reference`.
```

**Affected APIs**
- [Retrieve a list of Payment Request](/apis/poslink/apis#payment-requests)
- [Retrieve a Payment Request](/apis/poslink/apis#payment-requests)
- [Create a Payment Request](/apis/poslink/apis#payment-requests)

**Why This Change?**

The `source_reference_id` is currently used across various internal and external systems inside Teya, which has led to inconsistencies and confusion across services.

To provide a clear, unified reference for merchants and developers, we are consolidating this field under a single standard: `merchant_reference`

**Example Response Before and After**

```tabs
    tab:
      title: Before (Past Response)
      content:
        ```json
        {
          "payment_request_id": "xxx",
          "source_reference_id": "some_ref_123"
        }
        ```
    tab:
      title: After (New Response)
      content:
        ```json
        {
          "payment_request_id": "xxx",
          "source_reference_id": "some_ref_123",
          "merchant_reference": "some_ref_123"
        }
        ```
```

```admonition
icon: fas fa-info-circle
content: For a transitional period, both fields may appear in responses, but `source_reference_id` will return Null
```

**Action Required**

Please update your ePOS integration to:

1. Stop using `source_reference_id` in your logic and data pipelines.
2. Start using `merchant_reference` instead.

```admonition
icon: fas fa-exclamation-triangle
content: The `source_reference_id` field will be fully removed on **September 19, 2025** (3 months from the announcement).

Failure to make this change may result in loss of reference data or issues in your internal reconciliation processes once the deprecated field is fully removed.
```

---

## June 11, 2025 - **Added**

### Idempotency-Key Header Support

Added support for the `Idempotency-Key` header for the Create Payment Request endpoint.

Please see section [Send a payment request](/apis/poslink/apis#payment-requests)

---

## May 15, 2025 - **Changed**

### Technical Change Description

Effective May 15, 2025, POSLink will improve the metadata experience by changing the source of the data when a transaction is approved. This will ensure metadata becomes available to partners in under 3 seconds, enhancing the responsiveness of the Get a Payment Request API.

As part of this update, the structure of the metadata field in the API response will be slightly adjusted.

**API Response Changes**

```tabs
    tab:
      title: Current API Response
      content:
        ```json
        {
          "payment_request_id": "bee17dec-01dd-4ee5-a17d-ec01dd2ee5ca",
          "requested_amount": {
            "currency": "GBP",
            "amount": 70,
            "tip": 0
          },
          "status": "SUCCESSFUL",
          "transaction_type": "SALE",
          "created_at": "2022-06-15T16:24:120Z",
          "updated_at": "2022-06-15T16:26:120Z",
          "source_reference_id": "423897430",
          "transaction_id": "te3c89aa-d84f-4916-b88b-7e6a051765fa",
          "gateway_payment_id": "39e3bacdd5d38d9ce611cf88afbcc86df829a9a5641880b3",
          "terminal_id": "70dc65ba-1c13-492a-82a0-15821e5f63ba",
          "store_id": "f04fe1ce-e7bd-4c5b-b873-b156643c0bc3",
          "metadata": {
            "payment_method_details": {
              "card": {
                "last4": "1234",
                "issuing_country": "GB",
                "brand": "MASTERCARD",
                "type": "CREDIT"
              },
              "entry_mode": "CONTACTLESS",
              "verification_method": "OFFLINE_PIN",
              "application_id": "A0000000041010",
              "mid": "5006544",
              "response_code": "00",
              "authorisation_code": "A8RLR8"
            }
          }
        }
        ```
    tab:
      title: Expected API Response (Effective May 15, 2025)
      content:
        ```json
        {
          "payment_request_id": "bee17dec-01dd-4ee5-a17d-ec01dd2ee5ca",
          "requested_amount": {
            "currency": "GBP",
            "amount": 70,
            "tip": 0
          },
          "status": "SUCCESSFUL",
          "transaction_type": "SALE",
          "created_at": "2022-06-15T16:24:120Z",
          "updated_at": "2022-06-15T16:26:120Z",
          "source_reference_id": "423897430",
          "transaction_id": "te3c89aa-d84f-4916-b88b-7e6a051765fa",
          "gateway_payment_id": "39e3bacdd5d38d9ce611cf88afbcc86df829a9a5641880b3",
          "terminal_id": "70dc65ba-1c13-492a-82a0-15821e5f63ba",
          "store_id": "f04fe1ce-e7bd-4c5b-b873-b156643c0bc3",
          "metadata": {
            "payment_method_details": {
              "card": {
                "last4": "1234",
                "brand": "MASTERCARD",
                "bin": "123456"
              },
              "entry_mode": "CONTACTLESS",
              "verification_method": "OFFLINE_PIN",
              "application_name": "Debit MasterCard",
              "application_id": "A0000000041010",
              "mid": "5006544",
              "response_code": "00",
              "authorisation_code": "A8RLR8"
            }
          }
        }
        ```
```

**Summary of Changes**

```grid
card:
    title-left: Deprecated Fields
    icon: fas fa-times-circle
    content:
      • `issuing_country` (UK, HUN, HRV)
      • `type` (CREDIT / DEBIT)
card:
    title-left: New Fields
    icon: fas fa-plus-circle
    content:
      • `bin` (e.g. 518637)
      • `application_name` (e.g. Debit MasterCard)
```

**Partner Impact**

Each partner is encouraged to review and analyse their current integration to assess whether any adjustments are necessary to support the updated metadata structure.

```admonition
icon: fas fa-exclamation-triangle
title: Deprecated Fields
content: | 
  Issuing Country and Card Type
    • These fields will be deprecated and return null in the API response
    • They will be removed from POSLink on May 31, 2025
    • **Action Required:** Partners should update their integrations to remove any dependency on these deprecated fields.
```

```admonition
icon: fas fa-plus-circle
title: New Fields
content: |
  Card Bin, APN (Application Preferred Name)

    • A new field, card bin and application preferred name will be included in the API response.
    • This provides the first 6-8 digits of the card number and card application related.
    • **Action Required:** Partners will have to update their ePOS system if they wish to include the new fields (Card Bin & Application Preferred Name).
```

**Merchant Impact**

This change is expected to have a positive impact for merchants. For setups where the merchant's system relies on metadata to print receipts, this data will now be available in less than 3 seconds after the transaction is approved. This helps to:

- Reduce delays in receipt printing
- Avoid cancelled or duplicate requests due to missing metadata

No action is required from merchants to benefit from this improvement.

---

## Oct 17, 2024 - **Added**

### Add validation on Store ID and Terminal ID

POSLink is introducing a new validation to ensure that the Terminal ID belongs to the given Store ID in Create a Payment Request. If the Terminal ID provided doesn't belong to the Store ID, POSLink will reject this request with the below response:

```json
HTTP 403 Forbidden
{
  "code": "TERMINAL_NOT_REGISTERED_WITH_STORE",
  "description": "Terminal is not registered with the store provided in the request"
}
```

```admonition
icon: fas fa-clock
content:This validation will take effect starting **November 26, 2024, at 03:00 AM**.
```

---

## May 7, 2024 - **Changed**

### Major documentation updated

Introduction to the 4 Stages of Integration:

1. Stage 1 - Design
2. Stage 2 - Develop
3. Stage 3 - Test
4. Stage 4 - Get Certified

In addition to the above information, the following pages have been added:

- FAQ (Frequently Asked Questions)
- Integration Check List
- Template for Teya Terminal Setup

```admonition
icon: fas fa-minus-circle
content:The page "Request a Test Terminal" was removed
```

---

## April 1, 2024 - **Changed**

### URL Updates

URL updated in all documentation from:

```tabs
    tab:
      title: Old URLs
      content:
        ```
        https://identity.cloud.saltpay.co/
        https://api.cloud.saltpay.co/pos-link/
        ```
    tab:
      title: New URLs
      content:
        ```
        https://id.teya.com/
        https://api.teya.com/poslink/
        ```
```

---

## February 14, 2024 - **Changed**

### API Response Updates

- Response of **Retrieve a payment request** updated to include `mid`, in the metadata object, for all successful transactions.
- The `status` query parameter for the **Retrieve a list of payment requests** is now optional. If you omit the status query parameter, the returned list will include all payment requests.

---

## November 07, 2023

**Added**
- Added optional query parameters: `start_date_time` and `end_date_time` to the **Retrieve a list of payment requests** endpoint.
- Released an updated version of the cancel flow, allowing transactions to be canceled up until a card is presented to the terminal.

**Deprecated**
- Deprecated version 1 of the cancel flow in favour of version 2.

---

## September 28, 2023

**Added**
- **Transaction Metadata** - SUCCESSFUL response of Retrieve a payment request updated to include additional transaction metadata fields. This addition is intended to support various use cases, including consolidated receipt printing.

**Changed**
- Removed deprecation notice on `gateway_payment_id` which will replace `transaction_id` now marked for deprecation. (Deprecation date for this change is yet to be confirmed. We are committed to communicating this update well in advance to our valued partners, ensuring a seamless transition).

Impacted endpoints:
- Response of Retrieve a payment request
- Response of Retrieve a list of payment requests
- Request and Response of Create a new refund request

---

## September 04, 2023

**Added**
- Returning `terminal_id` in the following responses:
  - Response of Retrieve a payment request
  - Response of Retrieve a list of payment requests

**Changed**
- Added `transaction_id` as a replacement to `gateway_payment_id` which has been marked for deprecation (Deprecation date for this change is yet to be confirmed).

Impacted endpoints:
- Response of Retrieve a payment request
- Response of Retrieve a list of payment requests
- Request and Response of Create a new refund request

Either value may be used interchangeably until deprecation of `gateway_payment_id` has been finalised.

- Create a payment request response updated to include additional transaction fields

**Removed**
- `success` field in Cancel a payment request has been marked for deprecation. This can be inferred from `status` field. (Deprecation date for this change is yet to be confirmed).

---

## March 13, 2023 - **Initial Release**

### Initial release

The initial release of POSLink API documentation.