# Changelog

## v1.9.0 (2026-08-04)

### Summary
* ⚠️ Windows: this version is signed with a new certificate. If you verify the SDK's identity, replace the `signing_cert.cer` from the zip together with the app folder — the certificate you have from an earlier version will not match this executable. See [Updating to a new version](https://docs.teya.com/epos-sdk/poslink/windows/getting-started#updating-to-a-new-version).
    * Versions you already installed keep working, and nothing about how you verify changes.
* ⚠️ Android minimum supported versions change (see below). Your app will not compile until you update, so plan for it before you take this version.
    * iOS and Windows are not affected.
* Fixed an issue where All-in-One transaction-bound receipts did not consistently report the same `receiptId` on `PrintStateDetails`.
* Unreferenced refunds are now part of the common transactions API: `makeUnreferencedRefund` lives on `TeyaCommonTransactionsApi`, so the same call works across integration types instead of being PosLink-only.
  * ⚠️ Prefer `refundPayment` for refunds tied to a specific previous payment; use `makeUnreferencedRefund` only for card-present refunds not tied to any original payment.
* Android All-in-One now implements `makeUnreferencedRefund`.

### Android

#### PosLink & All-in-One
* `makeUnreferencedRefund` moved from `PosLinkTransactionsApi` up to `TeyaCommonTransactionsApi`. Existing PosLink integrations keep compiling and behaving exactly as before.
* Minimum versions changed to:
    * `compileSdk` -> `37`
    * `Android Gradle Plugin` -> `8.13.2`
    * `Gradle` -> `8.13`
    * `kotlin` -> `2.3.0`
* `minSdk` now depends on the integration type:
    * All-in-One -> `21`, lowered from `23`. If you held back on Teya because of the `23` floor, you can now support Android 5.0 devices.
    * PosLink -> `23`, no change. PosLink draws its own UI, so it pulls Compose, which needs `23`.
* Take AGP `8.13.2` exactly or newer, not just "some 8.13" — it is the version needed to read the `android-37` platform and to keep R8 happy with the SDK's Kotlin metadata.

#### All-in-One specific
* `makeUnreferencedRefund` is implemented over the All-in-One transport. The terminal always asks for the manager PIN before processing.
* `MissedResponseListener.onMissedUnreferencedRefundResponse` delivers the final state of an unreferenced refund whose response arrived after the ePOS process was killed and recreated.

### iOS PosLink
* No behavior change — `makeUnreferencedRefund` is now declared on the shared `TeyaCommonTransactionsApi`.

<br>

____

<br>

## v1.8.0 (2026-07-13)

### Summary
* ⚠️ Some Android types that used to live inside `PaymentStateSubscription` are now top-level types in the same `com.teya.unifiedepossdk` package. Nothing about their content changed — only the import needs fixing.
    * iOS and Windows are not affected.
* PosLink refunds now run through the upgraded refunds endpoint.
* 🚧 Experimental: PosLink can now be used as a library by a Windows ePOS app that runs on the JVM, instead of only as a subprocess.
  * Tests are ongoing, and we'll document the approach once we're confident in it.

### Android - PosLink & All-in-One

* ⚠️ Two types moved and must be updated: (compilation will fail otherwise)

| Was                                                                             | Now                                                    |
|---------------------------------------------------------------------------------|--------------------------------------------------------|
| `com.teya.unifiedepossdk.PaymentStateSubscription.PaymentStateDetails`          | `com.teya.unifiedepossdk.PaymentStateDetails`          |
| `com.teya.unifiedepossdk.PaymentStateSubscription.PaymentStateDetails.Metadata` | `com.teya.unifiedepossdk.PaymentStateDetails.Metadata` |

The old names are still there, but only so your IDE can fix the code for you. Put the caret on the old name and press `Alt`+`Enter` (`Option`+`Enter` on macOS), then pick **"Replace usages of ... in whole project"**. That updates every usage and import in one go. Nothing about their content changed — only the import needs fixing.

* Some other types have moved but in a non-breaking way — you should also update them the same way, but old symbols will still work.

<br>

____

<br>

## v1.7.0 (2026-07-09)

### Summary
* New `MotoFormShown` payment in-progress state, reported over PosLink while the operator keys in the card details by hand for a MOTO (Mail Order / Telephone Order) payment.
* New unreferenced refund on PosLink — return money to a card without an original sale. The customer taps their card at the terminal to receive the refund.
  * ⚠️ Prefer `refundPayment` for refunds tied to a specific previous payment; use `makeUnreferencedRefund` only for card-present refunds not tied to any original payment.
* New PosLink cancellation/failure reasons surfaced via new `PaymentStateReason` enum entries. Each shown in the built-in in-progress UI.
* 🚧 Changes on Purchase data experimental APIs:
  * `PurchaseData` now accepts:
    * `receiptNumber` to attach a pre-allocated fiscal receipt number to a payment. External ePOS apps that don't manage their own receipt series can leave it `null` (default) — no action required.
    * `purchaseStoreInfo` for attaching a merchant snapshot to a payment so it appears on the receipt header.

### Android 

#### PosLink & All-in-One 
* `PaymentStateSubscription` has a new `transactionType` property — `TransactionType.Payment` or `TransactionType.Refund` — telling you whether the subscription tracks a payment or a refund.
* `PaymentStateDetails` has a new `gatewayTransactionId` field (a `GatewayTransactionId`) — a `GatewayPaymentId` for a payment and a `GatewayRefundId` for a refund.
* `PaymentStateSubscription.PaymentStateReason` has new enum entries for PosLink request outcomes. The built-in in-progress UI shows a message for each.
* 🚧 Changes on Purchase data experimental APIs:
    * `PurchaseData` has two new optional constructor parameters:
        * `receiptNumber: String? = null` — fiscal receipt number pre-allocated by the ePOS. Pass `null` (default) if your app does not manage receipt series.
        * `purchaseStoreInfo: PurchaseStoreInfo? = null` — optional merchant snapshot for the receipt header. Pass `null` (default) to omit.

#### PosLink specific
* New `InProgressState.MotoFormShown` value (`PaymentStateSubscription.InProgressState`), reported through the payment state subscription while the operator types the card details by hand for a MOTO (Mail Order / Telephone Order) payment. Only delivered over the version-3 read; older reads surface `WaitingForCardEntry`. The pre-built PosLink payment UI shows a dedicated "Entering card details" title for this state.
* New `makeUnreferencedRefund` method on `PosLinkTransactionsApi`. It starts a card-present refund that credits the card presented at the terminal, not tied to any original payment, and returns a `PaymentStateSubscription` just like `makePayment`.
  * ⚠️ Prefer `refundPayment` for refunds tied to a specific previous payment; use `makeUnreferencedRefund` only for card-present refunds not tied to any original payment.

### iOS - PosLink
* New `TeyaInProgressState.MotoFormShown` value, reported through the payment state subscription while the operator types the card details by hand for a MOTO (Mail Order / Telephone Order) payment. Only delivered over the version-3 read; older reads surface `WaitingForCardEntry`. The pre-built PosLink payment UI shows a dedicated "Entering card details" title for this state.
* New `makeUnreferencedRefund` method on `PosLinkTransactionsApi`. It starts a card-present refund that credits the card presented at the terminal, not tied to any original payment, and returns a `PaymentStateSubscription` just like `makePayment`.
  * ⚠️ Prefer `refundPayment` for refunds tied to a specific previous payment; use `makeUnreferencedRefund` only for card-present refunds not tied to any original payment.
* `TeyaPaymentStateSubscription` has a new `transactionType` property — `TeyaTransactionType.payment` or `TeyaTransactionType.refund` — telling you whether the subscription tracks a payment or a refund.
* `TeyaPaymentStateDetails` has a new `gatewayTransactionId` field (a `TeyaGatewayTransactionId`) — a `TeyaGatewayPaymentId` for a payment and a `TeyaGatewayRefundId` for a refund.
* `TeyaPaymentStateReason` has new enum entries for PosLink request outcomes. The built-in in-progress UI shows a message for each.
* 🚧 Changes on Purchase data experimental APIs:
    * `TeyaPurchaseData` has two new fields:
        * `receiptNumber: String?` — fiscal receipt number pre-allocated by the ePOS. Pass `nil` if your app does not manage receipt series.
        * `purchaseStoreInfo: TeyaPurchaseStoreInfo?` — merchant snapshot for the receipt header. Pass `nil` to omit.

### Windows - PosLink
* New `MOTO_FORM_SHOWN` value on the `inProgressState` of a payment state change (JSON-RPC), reported while the operator types the card details by hand for a MOTO (Mail Order / Telephone Order) payment. 
  * ⚠️ If you are deserializing the `inProgressState` into an enum, make sure to have a fallback branch for unrecognized values so your integration keeps working as new states are introduced.
* New `makeUnreferencedRefund` JSON-RPC method. It starts a card-present refund that credits the card presented at the terminal, not tied to any original payment, and streams state updates just like `makePaymentAndSubscribe`.
  * ⚠️ Prefer `refundPayment` for refunds tied to a specific previous payment; use `makeUnreferencedRefund` only for card-present refunds not tied to any original payment.
* New streamed `makeUnreferencedRefund->onPaymentStateChanged` result. It mirrors `makePaymentAndSubscribe->onPaymentStateChanged` but carries a `gatewayRefundId` (the id of the created refund) instead of `gatewayPaymentId`.
* `PaymentStateReason` (JSON-RPC) has new enum entries.

<br>

____

<br>

## v1.6.0 (2026-06-10)

### Summary
* New Pay at Table support on POSLink - register tabs, subscribe to card machine-initiated tab events, and settle tabs (full or split) from your ePOS. See the per-platform Pay at Table guides below.
* Internal improvements.
* Changes on Purchase data experimental APIs:
  * New `TaxType` enum to classify line items as VAT-applicable or VAT-exempt
  * `Product` now carries `taxType` and `taxCode` fields, enabling per-item tax classification when sending basket data on checkout
* Fixed a crash on All-in-One when handling a missed print response for a custom (non-transaction) receipt.

### Android - PosLink

* New Pay at Table APIs on `PosLinkSDK`: a `tabsApi` for the tab lifecycle (open/list/get/close tabs, store-level toggle), a `tabEvents` subscription for card machine-initiated events, and a tab-aware `makePayment` overload. See the [Pay at Table guide](https://docs.teya.com/epos-sdk/poslink/android/pay-at-table).
* Changes on Purchase data experimental APIs:
  * New `TaxType` enum (`com.teya.feature.basketdata.TaxType`) with two values:
      * `Vat` - item is subject to VAT
      * `VatExempt` - item is VAT-exempt
  * `Product` has two new constructor parameters:
      * `taxType: TaxType?` - tax type classification for the line item
      * `taxCode: String?` - tax code string (e.g. `"VAT_STANDARD"`, `"VAT_REDUCED"`); pass `null` if not applicable

### iOS - PosLink
* New Pay at Table APIs on `PosLinkSDK`: a `tabsApi` for the tab lifecycle (open/list/get/close tabs), a `tabEvents` subscription for card machine-initiated events, and a tab-aware `makePayment` overload. See the [Pay at Table guide](https://docs.teya.com/epos-sdk/poslink/ios/pay-at-table).
* Changes on Purchase data experimental APIs:
  * New `TeyaTaxType` enum with two values:
      * `Vat` - item is subject to VAT
      * `VatExempt` - item is VAT-exempt
  * `TeyaProduct` has two new fields:
      * `taxType: TeyaTaxType?` - tax type classification for the line item
      * `taxCode: String?` - tax code string (e.g. `"VAT_STANDARD"`, `"VAT_REDUCED"`); pass `nil` if not applicable

### Windows - PosLink

* New Pay at Table JSON-RPC methods exposing the tab lifecycle (`openTab`, `listTabs`, `getTab`, `closeTab`, `setPayAtTableEnabledOnStore`), a `subscribeTabEvents` stream for card machine-initiated events (plus `respondToBillRequest`/`respondWithError`/`unsubscribeTabEvents`), and an optional `tabContext` on `makePaymentAndSubscribe` for settling tabs. See the [Pay at Table guide](https://docs.teya.com/epos-sdk/poslink/windows/pay-at-table).
* Changes on Purchase data experimental APIs:
  * The `product` object in basket line items now accepts two new optional fields:
      * `taxType` - one of `"Vat"` or `"VatExempt"`, or omit/`null` if not applicable
      * `taxCode` - tax code string (e.g. `"VAT_STANDARD"`, `"VAT_REDUCED"`), or omit/`null` if not applicable

<br>

____

<br>

## v1.5.0 (2026-04-13)

### Summary
* Simplified SDK APIs - `transactionsApi` and `printingApi` are now always available (non-nullable) after initialization
* New `setupAuthAndStore` method allows completing auth and store linking without card machine selection
* New `linkedStore` and `linkedTerminal` properties for granular access to linking state
* `clearUserAuth` now correctly clears also device and card machine linking

### Android / iOS

#### PosLink
* `transactionsApi` and `printingApi` are now non-nullable. They are always available on the `PosLinkSDK` instance - no need to check for null or wait for `setup` success.
* New `setupAuthAndStore` method - performs authentication and store linking without the card machine selection step. Use `linkTerminal` separately when you're ready to link a card machine.
* New read-only properties `linkedStore` and `linkedTerminal` for accessing the currently linked store and card machine individually.
* `linkedDeviceDetails` is now still non-null when **both** store and card machine are linked.
* `clearUserAuth()` now cascades: it clears user auth, then store link, then card machine link. Previously it only cleared user auth.

### Windows - PosLink
* Added new request method `setupAuthAndStore` which performs authentication and store linking without the card machine selection step. Response type is `setupAuthAndStore->onResponse` with `response`, `store`, and `debugErrorMessage` fields (same as `setup->onResponse` but without card machine info).

<br>

____

<br>


## v1.4.0 (2026-04-08)

### Summary
* Improved forward compatibility with backend changes
* PosLink - Added two new APIs to help dynamically link with card machines: `getTerminals` and `linkTerminal`.
* Android minimum supported versions change (see below)


### Android

#### General
* Minimum versions changed to:
  * `kotlin` -> `2.2.21`
  * `minSdk` -> `23`
    * Please contact us if you still have Android hardware running old OS versions: Lollipop aka Android 5.x (API 21 and API 22)
    * We may consider maintaining a special artifact for it if we have enough demand for it
    * Most official google libraries are dropping this support too (see [here](https://developer.android.com/jetpack/androidx/versions/all-channel#:~:text=Starting%20in%20June%202025%2C))

#### PosLink
* `PosLinkSDK` now has two new APIs:
  * `getTerminals` returns the list of card machines belonging to the currently linked store. Results are cached; pass `forceRefresh = true` to bypass the cache.
  * `linkTerminal` links to a card machine by its id (e.g. one returned by `getTerminals`), or pass `null` to show the SDK's card machine selection UI.

### Windows - PosLink
* Added new request method `getTerminals` which returns the list of card machines belonging to the currently linked store. Results are cached; pass `forceRefresh: true` to bypass the cache.
* Added new request method `linkTerminal` which links to a card machine by its `terminalId` (e.g. one returned by `getTerminals`), or pass `null` to show the SDK's card machine selection UI.

### iOS - PosLink
* `PosLinkSDK` now has two new APIs:
  * `getTerminals` returns the list of card machines belonging to the currently linked store. Results are cached; pass `forceRefresh = true` to bypass the cache.
  * `linkTerminal` links to a card machine by its id (e.g. one returned by `getTerminals`), or pass `nil` to show the SDK's card machine selection UI.

<br>

____

<br>

## v1.3.2 (2026-03-19)

**Changes from v1.3.1** _(and v1.3.1-hf01 for Windows SDK)_

### Summary
* Improved migration from Direct API integration to SDK
* Added "hasPrinter" check on All In One
* Added a "Missing permission" screen that shows up when trying to log in with a non-admin account
* General improvements and fixes

### Android

#### All in One
* New API to check whether connected device has printer: `AioReceiptPrintingApi.hasPrinter` method.

#### PosLink
* Advanced API `PosLinkSDK.AuthConfig.Delegated` now also has a way to pass in client id/secret. The SDK will use this if the provided user access token is not working in order to present the user with the login flow. If the passed in token is not working and no client id/secret was passed in, the `setup` flow will end in a `SetupFailure`.

### Windows - PosLink
* Added optional field `initialUserAccessToken` to the `"initialize"` method that the SDK will use to avoid showing the login flow. This is useful if you are migrating from a direct API integration and your users already are logged in in their ePOS applications. Upon successful response on the `setup` method, you can delete this token from your system.

### iOS - PosLink
* Advanced API `PosLinkSDK.AuthConfig.Delegated` now also has a way to pass in client id/secret. The SDK will use this if the provided user access token is not working in order to present the user with the login flow. If the passed in token is not working and no client id/secret was passed in, the `setup` flow will end in a `SetupFailure`.

<br>

____

<br>

## v1.3.1-hf01 (2026-02-03) - PosLink Windows only

**Changes from v1.3.1** _(1.3.1 should not be used for PosLink - Windows SDK, use 1.3.1-hf01 instead)_

### Windows - PosLink
* Fixed an issue with the `initialize` request introduced with 1.3.0

<br>

____

<br>

## v1.3.1 (2026-01-26)

**Changes from v1.2.0** _(1.3.0 was dropped, use 1.3.1 instead)_

### Summary
* Added DCC and transaction timestamp information on payment result related APIs.
* Added an optional `debugErrorMessage` to APIs that can fail (for logging, reporting issues to Teya, and self-diagnosis).
* Migrated to m2m tokens to avoid authorization being linked to specific users.
* Improved SSE client connection handling to avoid restarting the connection unconditionally after 10 seconds.

### Android

#### General (PosLink & All In One)
* Added new `dcc` field (a `Dcc` class) to `Metadata`
* Added new `transactionTimestamp` field to `PaymentStateDetails`
* Added new `debugErrorMessage` field to `PaymentStateDetails`, `RefundResultSubscription.ResultDetails` and `PaymentStateSubscription.CancellationResultInfo` (previously `PaymentStateSubscription.CancellationResult` enum which is now still available under new `CancellationResultInfo`)
* Added two new entries to `CardType` enum: `Private` and `DeferredDebit`

#### PosLink
* `PosLinkSDK.Failure` changed to `PosLinkSDK.SetupFailure` (the former is deprecated). The new class contains the same failure type enum and also includes `debugErrorMessage`, for logging, reporting issues to Teya, and self-diagnosis.

#### All In One
* Improved card-related data on `PaymentStateSubscription.PaymentStateDetails.Metadata.Card`

### Windows - PosLink
* Responses:
  * `setup->onResponse`, `makePaymentAndSubscribe->onPaymentStateChanged`, `cancelPayment->onResult` and `refundPayment->onResult` now include `debugErrorMessage`, for logging, reporting issues to Teya, and self-diagnosis.
  * `makePaymentAndSubscribe->onPaymentStateChanged` now has `transactionTimestamp` optional field, UTC epoch milliseconds for when transaction occurred.
  * `makePaymentAndSubscribe->onPaymentStateChanged` `metadata` object now has `dcc` optional field, a `Dcc` json object (check Windows API Reference for details).
  * `makePaymentAndSubscribe->onPaymentStateChanged` `metadata.card.type` enum has two additional possible values: `Private` and `DeferredDebit`.

### iOS - PosLink
* `PosLinkSDKFailure` changed to `PosLinkSDKSetupFailure`.
* Fixed an issue with a stuck loading UI in some edge cases.

<br>

____

<br>

## v1.2.0 (2025-11-03)

**Changes from v1.1.0**

### Android

#### General
* `GatewayTransactionId`, `GatewayPaymentId`, `GatewayRefundId` were moved from `com.teya.unifiedepossdk` to `com.teya.unifiedepossdk.models`
* `TeyaCommonTransactionsApi.Type` enum was moved to `com.teya.unifiedepossdk.models.IntegrationType`
* New `TeyaCommonPrintingApi` with two functions `printCustomTemplate` and `printCustomImage`

#### PosLink
* Minimum versions changed to:
  * `compileSdkVersion` -> `36`
  * `Android Gradle Plugin` -> `8.9.3`
* `setupTransactionsApi` deprecated. Use `setup` instead. `TeyaCommonTransactionsApi` is now available through a property called `transactionsApi` that is always available. It is technically nullable, but will not be null ever inside the `onSuccess` callback of the setup call, and for all usages between that and a clear method call.
* Added `transactionsApi` property to `PosLinkSDK` interface
* Added `printingApi` that returns a `TeyaCommonPrintingApi`, if `setup` was successful and no clear method was called. This printing API allows you to print receipts on the payments card machine.

#### All In One
* `MissedResponseListener`
  * `onMissedCustomReceiptResponse` added
  * `ReceiptPrintingApi.PrintResult` changed to `PrintStateDetails` on `onMissedReceiptResponse`
* `ReceiptPrintingApi` changed to `AioReceiptPrintingApi`
  * Has the same method for printing a transaction receipt
  * The way to get the result of that receipt has changed to be consistent with Custom Receipt actions
  * Has two new methods for printing custom receipts `printCustomTemplate` and `printCustomImage`
* `setupReceiptPrintingApi()` changed to `printingApi`

### Windows - PosLink

* Added new request method `printCustomTemplate`
* Added new request method `printCustomImage`

### iOS - PosLink

* Added `TeyaCommonTransactionsApi`
* Added `transactionsApi` property to `PosLinkSDK` interface
* Added `printingApi` that returns a `TeyaCommonPrintingApi`, if `setup` was successful and no clear method was called. This printing API allows you to print receipts on the payments card machine.


<br>

____

<br>

## v1.1.0 (2025-10-13)

**Changes from v1.0.1**

### Android - PosLink
- Support API 21
- Minimum supported version of Kotlin is now 2.1.21 (up from 2.0.0)
- In Progress Teya UI will now be more granular and provide additional information about what is happening in the Teya card machine.
- Added `InProgressState` to `PaymentStateDetails` updates
  - https://docs.teya.com/kotlin-docs/unified-epos-sdk/core-api/com.teya.unifiedepossdk/-payment-state-subscription/-in-progress-state/index.html

### Windows - PosLink
- In Progress Teya UI will now be more granular and provide additional information about what is happening in the Teya card machine.
- Added `inProgressState` to `makePaymentAndSubscribe->onPaymentStateChanged` response type

### iOS - PosLink
- First release of iOS SDK for PosLink

### General
- Translation improvements

<br>

____

<br>

## v1.0.1 (2025-08-04)

**Changes from v1.0.0**

### Windows - PosLink

Fixed: Resolved a self-cleanup issue. The SDK app process will now automatically terminate itself when the ePOS app process exits.

### All Platforms - PosLink & All In One

- Hungarian Forint (HUF) currency improvements:
  - Fixed inconsistencies between refund and payment APIs. Both APIs now expect real minor units, as documented.
  - All amounts provided by the SDK will now be consistent with this behavior:
    - Example: Consumers should pass 98700 for an amount of 987 HUF.
    - Note: If an amount that doesn't end with '00' is received for HUF, the SDK will throw an exception (or return an error response for Windows).
  - This update aligns with the ISO 4217 standard, which specifies two minor units for HUF, even though they are not commonly used in practice.
