Back to docs

Changelog

Stay up to date with the latest changes across Tapaya products.

  1. 1.19.1

    Accept Android 1.19.1

    Fixed

    Fixed

    • Terminal activation could reject a valid activation code when the SDK authenticated before the companion was installed.
  2. 1.19.0

    Accept Android 1.19.0

    Changed

    Changed

    • AcceptAuth.authenticate() uses the device id owned by the companion app when it reports one, so every host app on a device, and a host app reinstalled after an uninstall, is the same device on the backend. The stored id, then a new random one, are used only while no companion can answer. A companion build that predates this reports no id, and the SDK behaves as before.
    • PluginStatus.MerchantMismatch (and PluginMerchantMismatch) are also reported when the companion is activated for a different device, not only a different merchant. The remedy is the same: logout(), then activate again. Devices are compared only once the SDK has authenticated.
  3. 1.18.0

    Accept Android 1.18.0

    Added

    Added

    • NfcPositionConfig.ExternalReader takes an optional indicator: ReaderIndicator, telling the companion which screen edge (ReaderEdge) the external reader sits beyond and where along it (offsetFraction, 0 to 1). The tap screen then shows animated chevrons pointing at the reader, for kiosks and docks where the reader is outside the screen. Null keeps today's behavior, and a companion build that predates the option ignores it.
  4. 1.17.0

    Accept Android 1.17.0

    AddedFixed

    Added

    • CustomerFacingFlipConfig on AcceptPayments.setOptions and AcceptPayments.pay, controlling whether the companion rotates the payment UI 180° when the merchant turns the device toward the customer. Disabled turns it off for hardware that is already customer-facing, such as a fixed POS, a dual-sided panel, or a device in a stand. On those the turn never happens and the motion sensors only produce accidental flips. Defaults to Automatic, which is the existing behavior; a companion build that predates the option ignores it.

    Fixed

    • AcceptPlugin.activateTerminal() throws PluginUnavailable, as documented, when the plugin is not installed or cannot handle activation. It returned ActivateTerminalResult.Failed(UNKNOWN) instead, after needlessly generating a handover code.
  5. 1.16.0

    Accept Android 1.16.0

    AddedChanged

    Added

    • AcceptPlugin.updateInfo() answers from the backend's release metadata, unauthenticated, against the installed package, so it works with no store and with the plugin absent. A Play-installed plugin is still measured against Play, since a release reaches the backend while the same build can sit in review; the plugin's own check stays the fallback.
    • accept-installer: new optional artifact, com.tapaya:accept-installer. On a storeless device AcceptPlugin.install() downloads the APK and installs it through the system installer. Depending on the artifact is the opt-in — it carries REQUEST_INSTALL_PACKAGES, which Play requires integrators to declare, and :accept never asks for it. The APK is verified against its SHA-256, declared package and version code, a pinned signer, and the installed plugin's own signer before anything is committed.
    • PluginStoreUnavailable, PluginSelfInstallUnavailable, PluginInstallPermissionRequired, PluginInstallAuthRequired and PluginDownloadNotPermitted errors from AcceptPlugin.install() — no store, no installer artifact, no "Install unknown apps" grant, no merchant session, or a merchant the backend does not allow the APK. The last is an entitlement decision rather than anything retryable: point the merchant at their account manager or developers@tapaya.com.

    Changed

    • AcceptPlugin.install() no longer always opens a store listing: with no store it takes the download path above, which needs an authenticated merchant and says so before the transfer starts rather than after.
  6. 1.15.0

    Accept Android 1.15.0

    Fixed

    Fixed

    • Payments failed with LocationUnavailable or LocationTimeout on terminals whose fused provider reports itself present and enabled but never produces a fix. On API 31+ a live fix was requested from fused alone, so a null or silent answer ended the request even while network and gps were enabled and working. A live fix now races every enabled provider at once and takes the first to answer, failing only once all of them have answered without a location. The OS last-known lookup that seeds the cache also covers fused and passive now, so a cold start more often avoids blocking at all.
  7. 1.14.2

    Accept Android 1.14.2

    Changed

    Changed

    • Payments no longer wait on a location fix. Every pay() used to race a live fix against a timeout before the payment could be created, so a terminal on a weak location stack paid that latency on every transaction and reached its last-known fix only after the timeout had already been spent. The most recent known fix is now served immediately, and is refreshed in the background — off the payment path — once it is older than an hour. The cache is seeded from the OS last-known location on a cold start, so only a terminal that has never held a fix blocks at all, and that first wait is capped at 30 seconds. A terminal does not move between transactions, so an hour-old fix describes its location as well as a fresh one. One consequence worth knowing: a cached fix no longer has an upper age bound, so a terminal that has been offline for days serves a days-old fix and refreshes afterwards.
  8. 1.14.1

    Accept Android 1.14.1

    Fixed

    Fixed

    • Payments on devices with a weak or non-GMS location stack failed with LocationUnavailable even though the device held a usable fix. The fused provider returned nothing within FRESH_FIX_TIMEOUT_MS, and the last-known fallback then rejected the only fix on the device because MAX_CACHED_LOCATION_AGE_MS was 2 minutes — on a stationary countertop terminal the last fix is routinely tens of minutes old. The cached/last-known window is now 30 minutes, so the fallback accepts the fixes it exists to accept. A terminal does not move between transactions, so a half-hour-old fix describes its location as well as a fresh one; the fresh-fix attempt still runs first and is still preferred when it succeeds.
  9. 1.14.0

    Accept Android 1.14.0

    AddedFixed

    Added

    • Accept.setTheme() / getTheme() let host apps forward org branding (colors + logos) to the companion app's activation, status, and payment screens. AcceptTheme mirrors the existing org-theme wire format field-for-field, pushed to the plugin via the setTheme() AIDL call and a THEME_JSON intent extra on PAY/ACTIVATE_TERMINAL/WARM_UP. setTheme() persists until changed or cleared (null, or clear()) — it's session-wide branding, not a per-payment override — and is safe to call before or after initialize().
    • Accept.createLocalThemeImageUri() covers logos the host app has locally (e.g. picked from the photo gallery) rather than hosted at a stable URL: writes the bytes to SDK-private storage and returns a content:// URI the companion is granted read access to, usable anywhere AcceptTheme's image fields take a URL.

    Fixed

    • activateTerminal() now fails fast with MerchantOnboardingIncomplete when the merchant hasn't finished onboarding or its card payment method isn't ready, instead of proceeding to build the intent and launch the plugin activity. The gate had been temporarily disabled while merchant onboarding was being fixed on the backend; it's re-enabled now that the backend fix has shipped.
    • Plugin binder calls (bind/connect/AIDL call) now run on Dispatchers.IO instead of whatever dispatcher the caller launched on. The cold-bind wait (up to BIND_TIMEOUT_MS) previously ran on Main by default when called from a ViewModel's viewModelScope.launch, freezing input dispatch and risking an ANR. setTheme() is also marked oneway, so pushing a theme never waits on the companion at all.
  10. 1.13.0

    Accept Android 1.13.0

    ChangedFixed

    Changed

    • A plugin bind that fails now says why. PluginUnavailable used to be raised behind a single plugin bind failed line, which reads identically whether the plugin is not installed, installed but disabled, uninstalled-for-this-user with its data kept, or merely invisible because the host app's merged manifest is missing the <queries> entry API 30+ package visibility requires. The SDK now tells those four apart and logs the distinction to integrators, alongside the counts of services that resolved with and without disabled components, the plugin's version and install source, and which other environment's plugin build is on the device. A successful bind records the same identity once, and again whenever it changes, so a later failure can be read against a baseline instead of in isolation — a version skew and a plugin disabled after the fact no longer look alike in a field report. Diagnostics only: no public type changed, and isInstalled() still answers exactly what it did before, a disabled plugin included.

    Fixed

    • Every failed bind leaked a ServiceConnection. bindService() registers the connection before it asks the system to bind, so neither a false return nor a thrown SecurityException unregisters it, and the host Context accumulated one leaked connection per failure (ServiceConnectionLeaked). Both paths now unbind.
    • A SecurityException from bindService() — the plugin's service not exported to the host app, or gated behind a permission it does not hold — propagated to the caller as-is instead of the PluginUnavailable the API documents. It is now caught, logged with its cause attached, and reported as PluginUnavailable.
    • A plugin whose process died before it connected — killed, updated, or force-stopped mid-bind — made the caller wait out the full bind timeout for a connection that was never coming. The binding's death now fails the call immediately.
  11. 1.12.0

    Accept Android 1.12.0

    Added

    Added

    • The hosted receipt page's URL is now available from the payment flow itself, instead of only from a later PaymentStatus lookup. PaymentEvent.Created carries receiptUrl alongside the payment token — so the link is in hand before the plugin is even launched — and PayResult.Success / PayResult.Declined carry it too, so a terminal result is self-contained. The URL resolves to the finished receipt once the payment settles; the link itself is stable from creation. Both fields are nullable and default to null, so existing construction and copy() calls keep compiling.
  12. 1.11.0

    Accept Android 1.11.0

    Added

    Added

    • NfcPositionConfig.ExternalReader for setups where the antenna is on a separate reader that is not above the device — a counter reader, a side-mounted pinpad, a customer-facing dock. There is no point on the device to place and no direction to point at, so the companion drops its tap indicator entirely and shows the amount with a prompt underneath it instead. Its optional message replaces the companion's own localized prompt for setups the default wording doesn't describe; you own its localization, blank counts as unset, and the companion trims and clamps it. Companion app 1.5.2 or newer is required — older builds treat the new mode as no override at all and keep resolving antenna position themselves, so nothing breaks.
  13. 1.10.0

    Accept Android 1.10.0

    AddedChanged

    Added

    • AcceptPlugin.activateTerminal() now throws NoTidsAvailableForMerchant when the merchant has no unassigned terminal (TID) left to activate, instead of a generic Unknown error.
    • Dual-sided ("double-sided") device support: Accept.displays (all(), customerFacing(), isDualScreen) reports the device's screens, and the new PaymentDisplay option on AcceptPayments.setOptions(display = ...) / pay(display = ...) runs the plugin's payment UI on the customer-facing panel while the host app keeps the merchant one. A target that can't be honored falls back to the default display, so single-screen behavior is unchanged. The terminal warm-up fired by authenticate() follows the same target. New :dualscreen sample app shows the full two-panel checkout.

    Changed

    • PayHostActivity now declares an empty taskAffinity, so a payment always starts a fresh task instead of stacking onto the host app's. Required for the cross-display launch above; on a single-screen device the only visible difference is that the invisible host no longer joins the host app's back stack.
    • The SDK's remote diagnostics now identify the device behind a log line: device id, brand, model, OS version, and the host app's package name, plus a one-time record of the device's display layout at initialize(). Internal diagnostics only — nothing about the merchant's customers is collected, and the sink stays off entirely in debug builds.
  14. 1.9.1

    Accept Android 1.9.1

    Fixed

    Fixed

    • Location fixes now fall back to the OS's last-known location when a fresh fix times out or the live request reports unavailable, instead of failing outright. On Android 11 (API 30), LocationManager.getCurrentLocation() is no longer used — it's unreliable on that API level — in favor of a one-shot requestLocationUpdates() request. Also guards against duplicate/late location callbacks and prefers the network provider before GPS.
  15. 1.9.0

    Accept Android 1.9.0

    Added

    Added

    • AcceptPlugin.updateInfo() reports whether a newer version of the plugin app is available on Play (PluginUpdateInfo: UpToDate / UpdateAvailable(priority) / Unknown). The plugin app checks itself via Play Core's in-app update API and reports the result over the existing status channel — the SDK never queries Play directly. Requires a plugin app build that sets the new update_available/update_priority status fields; older plugin builds report Unknown.
  16. 1.8.0

    Accept Android 1.8.0

    Added

    Added

    • ReceiptDetails on PayResult.Success/PayResult.Declined exposes structured card-receipt data reported by the terminal — merchant ID, terminal ID, card brand, EMV application label/AID, masked PAN, response code, and an ISO-8601 transaction timestamp — for callers that print their own official card receipt instead of relying solely on PaymentStatus.receiptUrl's hosted HTML page. Every field is optional/best-effort.
  17. 1.7.0

    Accept Android 1.7.0

    AddedChangedFixed

    Added

    • Optional transactionTimeout (Duration) on AcceptPayments.pay() and setOptions() controls how long the companion waits for a card tap. Validated to 0..120 seconds; out-of-range surfaces as TransactionTimeoutOutOfRange via PaymentEvent.CreationFailed (pay() never throws synchronously).

    Changed

    • AcceptPayments.refund() is now public (previously internal and unreachable by SDK consumers), matching cancel()'s KDoc/throws style.

    Fixed

    • Consumer ProGuard/R8 rules: AcceptException subtypes not ending in Exception are now kept by inheritance instead of name-suffix matching, so future subtypes can't fall through the cracks. Also keeps AcceptLogLevel, and scopes the Parcelable CREATOR keep rule to the SDK's own package instead of the whole app.
  18. 1.6.0

    Accept Android 1.6.0

    AddedChangedFixed

    Added

    • Optional tip (Long, minor units) on AcceptPayments.pay() — when set, the plugin skips its own interactive tip screen and charges amount + tip.
    • PayResult.Success.authCode exposes the processor authorization code reported by the terminal. Nullable/informational; may be absent depending on the processor.
    • ReceiptPrintBehavior on PaymentReceiptConfig.Show (Automatic, OnDemand, Disabled) controls when the companion prints the physical receipt. Defaults to OnDemand.
    • nfcPosition payment config hint (NfcPositionConfig) tells the companion where the device's NFC antenna is, to place the tap animation correctly. Defaults to Unspecified.
    • Optional metadata param on AcceptPayments.pay(), threaded through to the plugin and echoed back on all PayResult variants.

    Changed

    • Payment extras are no longer logged in full (extras=...) to avoid leaking metadata values; only extra keys are logged now.

    Fixed

    • Removed dead AcceptService/AcceptConfigProvider manifest entries.
  19. 1.5.0

    Accept Android 1.5.0

    AddedChanged

    Added

    • Accept.sdk.version, Accept.sdk.isProduction, and Accept.sdk.deviceId() for diagnostics and support — version is available before initialize(); isProduction reflects the active environment; deviceId() is a stable, DataStore-backed identifier available after authenticate().
    • PaymentReceiptConfig controls the receipt screen the companion shows after an *approved* payment: DismissImmediately, or Show(showQrCodeReceipt, dismissBehavior) with DismissBehavior.Manual or DismissBehavior.Delayed(duration). Set a default via AcceptPayments.setOptions(receiptConfig), or override per call via pay(..., receiptConfig). Has no effect on declined, reversed, or pending-reversal outcomes.

    Changed

    • The plugin's terminal now pre-warms in the background. Pure optimization — silent no-op until the companion app supports it; the pay path is unaffected either way.
  20. 1.4.3

    Accept Android 1.4.3

    AddedChanged

    Added

    • Accept.setLogLevel(AcceptLogLevel) for finer control over diagnostic log verbosity, with the new AcceptLogLevel enum (NONE, ERROR, WARN, INFO, DEBUG, VERBOSE). Defaults to DEBUG against sandbox and NONE against production.
    • Accept.setLogger(AcceptLogger?) to route consumer-facing SDK logs into a custom sink (Timber, Crashlytics, etc.); pass null to restore the default Logcat sink. Only already-redacted, consumer-facing messages reach the logger.

    Changed

    • Accept.setDebugLoggingEnabled(enabled) is now shorthand for setLogLevel: true maps to AcceptLogLevel.DEBUG, false to AcceptLogLevel.NONE. Prefer setLogLevel for finer control.
  21. 1.4.2

    Accept Android 1.4.2

    Changed

    Changed

    • The published -sources.jar and API reference documentation now contain only the public API;
  22. 1.4.1

    Accept Android 1.4.1

    Fixed

    Fixed

    • CI: publish the API reference documentation site on release. No functional changes to the SDK from 1.4.0.
  23. 1.4.0

    Accept Android 1.4.0

    AddedChanged

    Added

    • New Accept entry point exposing SDK lifecycle as an observable state: StateFlow<SdkState>.
    • AcceptAuth.authenticate(merchantToken) for merchant authentication.
    • AcceptSdk.minimumAmounts() for merchant-configured minimum payment amounts per currency.
    • AcceptMerchant surface: info(), config(), onboardingStatus(), availableCurrencies().
    • AcceptPayments.pay() returning a Flow<PaymentEvent> (Creating, Created, Launched, Result, CreationFailed), plus status() and cancel().
    • PaymentEvent.Created — the payment token is now available as soon as the backend creates the payment, before the plugin is launched.
    • AcceptPlugin surface for the Accept terminal companion app: isInstalled(), install(), status(), activateTerminal(), and logout().
    • pay() now fails fast with PluginNotReadyForPayments if the plugin isn't authenticated and ready, instead of surfacing a downstream plugin error.
    • Typed, sealed AcceptException hierarchy for public failure modes (auth, plugin, location, network, payment) — see KDoc @throws on each function for the exact set.
    • Accept.clear() to reset locally persisted SDK state on logout.
    • Accept.setDebugLoggingEnabled() for opt-in internal debug logging.
    • Location fix caching to speed up payment creation.

    Changed

    • pay() is now Flow-based instead of Activity-for-result; results are correlated by request ID and concurrent launches are rejected with PaymentInProgress.
    • Terminal activation is now a suspend function guarded against concurrent launches (ActivationInProgress).
    • Default environment is SANDBOX; target production explicitly via Accept.initialize(context, isProduction = true).
  24. 1.3.2

    Accept Android 1.3.2

    Fixed

    Fixed

    • AcceptUnknownException is now always constructed with a message, improving error reporting.
    • Companion-app discovery now matches only com.tapaya.accept.* packages.
    • Removed a hardcoded demo token.
  25. 1.3.1

    Accept Android 1.3.1

    Changed

    Changed

    • Updated sandbox base URL to api.sandbox.tapaya.com.
    • Example app rewritten to match the iOS example app flow: initialize → login (with auto-register on 401/404) → authenticate state machine, KYB, onboarding status, card status, and companion install/pair.
  26. 1.3.0

    Accept Android 1.3.0

    AddedChanged

    Added

    • Optional com.tapaya:accept-stripe module providing embedded Stripe Tap to Pay. The core com.tapaya:accept artifact no longer bundles the Stripe Terminal SDK.
    • Companion-app management API on Accept: isCompanionAppInstalled(), pairWithCompanionApp() and presentCompanionAppSheet().

    Changed

    • Reduced size of Accept SDK.
    • Companion app hand-off now uses an Android Intent instead of a com.tapaya.accept:// deep link.