Skip to main content

Gateway Android SDK

Overview

gateway-sdk-android has three package tiers:

  • com.myriad.gateway.sdk.android Standard Android wrapper for the plain Gateway admin/pay HTTP clients.
  • com.myriad.gateway.sdk.android.host The primary terminal/runtime SDK surface for apps that need to support both Nexgo and Tap to Pay without caring that SmartConnect exists internally.
  • com.myriad.gateway.sdk.android.referencehost Optional managed-host tooling for registration, heartbeat shaping, workspace snapshots, and operator-facing device-management flows.

Everything under com.myriad.gateway.sdk.android.smartconnect is internal implementation detail and should not be imported by app code.

Choose Your Path

HTTP-only Android app

Use:

  • GatewayAndroidConfig
  • GatewayAndroidClient

This is just the Android-friendly shell around the core Kotlin SDK.

Embedded terminal app

Use:

  • GatewayAndroidApp
  • GatewayAndroidHostRuntimeConfig
  • GatewayAndroidDeviceRuntimeConfig
  • GatewayAndroidHostState
  • GatewayAndroidUiState

This is the default integration path for a POS app that needs one API surface for both Nexgo and Tap to Pay.

Managed host / device-management app

Use referencehost only if the app also needs:

  • device registration payloads
  • heartbeat payloads
  • workspace snapshots
  • command or operator-facing host tooling

Primary types:

  • GatewayAndroidReferenceHost
  • GatewayAndroidReferenceHostLauncher
  • GatewayAndroidReferenceHostApp
  • GatewayAndroidDeviceManagementSurface

Package Structure

com.myriad.gateway.sdk.android

Purpose:

  • normal Gateway HTTP clients on Android
  • lifecycle-friendly wrapper over the core Kotlin SDK

Files:

  • GatewayAndroidConfig.kt
  • GatewayAndroidClient.kt

com.myriad.gateway.sdk.android.host

Purpose:

  • public terminal/runtime API
  • public state, snapshot, config, transaction, recovery, and bootstrap models

The main entrypoint is GatewayAndroidApp.

Important model groups:

  • runtime and device selection
  • host state and UI state
  • recovery and replay inspection
  • transport and bootstrap primitives

com.myriad.gateway.sdk.android.referencehost

Purpose:

  • managed-host and device-management tooling
  • registration and heartbeat request shaping
  • workspace and operator snapshot helpers

This package is optional. Treat it as an additive tooling layer, not the default way to start taking payments.

The public device-management requirement models also live in gateway-sdk-android itself, so Android consumers do not need a separate soft-pos-sdk artifact just to inspect readiness, attention level, or queued device-management work.

com.myriad.gateway.sdk.android.host.internal

Purpose:

  • seam/orchestration layer behind the public API

These classes exist to keep the public package small:

  • GatewayAndroidHostAdapter
  • GatewayAndroidAppSession
  • GatewayAndroidHostSession
  • GatewayAndroidHostManager
  • GatewayAndroidHostIntegration

They should not be part of the integration story.

com.myriad.gateway.sdk.android.smartconnect

Purpose:

  • runtime implementation
  • transport
  • recovery persistence
  • replay durability
  • protocol-specific storage and state

Apps should not import this package directly.

Core Concepts

GatewayAndroidHostRuntimeConfig

This is the base runtime wiring:

  • filesDir
  • transport
  • storage location strategy
  • terminal platform info collector
  • recovery backfill client
  • clock / operation id hooks
  • gateway name

The default terminalPlatformInfoCollector best-effort gathers Android device metadata for device-management payloads, so apps do not need to hand-build the full terminal profile just to register a device or send heartbeats.

GatewayAndroidDeviceRuntimeConfig

This is how the app declares device family:

  • GatewayAndroidDeviceFamily.NEXGO
  • GatewayAndroidDeviceFamily.TTP

That config resolves into GatewayAndroidDeviceRuntimeSelection, which keeps the selected runtime label and gateway name consistent.

GatewayAndroidApp

This is the main product surface.

It owns:

  • startup / reload
  • transaction execution
  • pending-operation recovery
  • offline server replay queue management
  • app snapshot/state projection

GatewayAndroidAppSnapshot

This is the “what should the app render right now?” model.

It includes:

  • runtime readiness
  • selected device family/runtime
  • recovery inspection
  • replay backlog state
  • terminal-device snapshot
  • device-management snapshot when applicable

GatewayAndroidTerminalPlatformInfo

This is now primarily an override model, not a required full payload.

The SDK auto-collects best-effort Android metadata for registration, heartbeat, and managed-host snapshots:

  • manufacturer
  • model
  • Android version
  • screen resolution
  • timezone
  • battery / charging status when available
  • network type when available

If the app wants to override specific fields, pass only those fields in GatewayAndroidTerminalPlatformInfo; the SDK merges them on top of the collected metadata.

GatewayAndroidHostState and GatewayAndroidUiState

Use these for app rendering:

  • GatewayAndroidHostState runtime truth: lifecycle, pending recovery, replay backlog, attention level
  • GatewayAndroidUiState app-facing banner and actionable recovery items

Storage and Key Material

The public bootstrap primitives are now real GatewayAndroid* types:

  • GatewayAndroidStoreLocationStrategy
  • GatewayAndroidDefaultStoreLocationStrategy
  • GatewayAndroidStoragePaths
  • GatewayAndroidKeyProvider
  • GatewayAndroidStaticKeyProvider
  • GatewayAndroidRootKeySource
  • GatewayAndroidStaticRootKeySource
  • GatewayAndroidDerivedKeyProvider
  • GatewayAndroidInitializer

That means app code no longer has to import SmartConnect-branded bootstrap types just to configure local storage or encryption keys.

Typical Embedded Runtime Setup

import com.myriad.gateway.sdk.android.host.GatewayAndroidApp
import com.myriad.gateway.sdk.android.host.GatewayAndroidDeviceFamily
import com.myriad.gateway.sdk.android.host.GatewayAndroidDeviceRuntimeConfig
import com.myriad.gateway.sdk.android.host.GatewayAndroidHostRuntimeConfig
import com.myriad.gateway.sdk.android.host.GatewayAndroidStaticRootKeySource

val runtimeConfig =
GatewayAndroidDeviceRuntimeConfig(
family = GatewayAndroidDeviceFamily.NEXGO,
runtime = GatewayAndroidHostRuntimeConfig(filesDir = filesDir),
)

val app =
GatewayAndroidApp.withDeviceRuntime(
deviceRuntimeConfig = runtimeConfig,
rootKeySource = GatewayAndroidStaticRootKeySource(rootKeyBytes),
)

val started = app.ensureStarted()
if (started.canTakePayment) {
// Render payment-ready UI.
}

Managed Host Example

import com.myriad.gateway.sdk.android.host.GatewayAndroidDeviceFamily
import com.myriad.gateway.sdk.android.host.GatewayAndroidDeviceRuntimeConfig
import com.myriad.gateway.sdk.android.host.GatewayAndroidHostRuntimeConfig
import com.myriad.gateway.sdk.android.host.GatewayAndroidStaticRootKeySource
import com.myriad.gateway.sdk.android.host.GatewayAndroidTerminalPlatformInfo
import com.myriad.gateway.sdk.android.referencehost.GatewayAndroidReferenceHost

val referenceHost =
GatewayAndroidReferenceHost.withRootKeySource(
deviceRuntimeConfig =
GatewayAndroidDeviceRuntimeConfig(
family = GatewayAndroidDeviceFamily.TTP,
runtime = GatewayAndroidHostRuntimeConfig(filesDir = filesDir),
),
rootKeySource = GatewayAndroidStaticRootKeySource(rootKeyBytes),
)

val started = referenceHost.ensureStarted()
val registration = started.registrationRequest(deviceId = "device-123")

val managedHost =
started.managedHostSnapshot(
deviceId = "device-123",
platformInfo = GatewayAndroidTerminalPlatformInfo(deviceName = "Front Counter"),
)

Recovery Model

The Android runtime supports two operational recovery concepts:

  • pending-operation recovery
  • offline server replay queue flushing

It does not expose a fake offline terminal authorization mode. The public API is intentionally explicit about that boundary.

Key public types:

  • GatewayAndroidPendingOperation
  • GatewayAndroidRecoveryInspection
  • GatewayAndroidRecoveryResolution
  • GatewayAndroidRecoveryItem

Migration Rule

For any new Android integration:

  • import from host for normal runtime/payment work
  • import from referencehost only for device-management tooling
  • do not import from smartconnect

If app code knows smartconnect exists, the package boundary is being used incorrectly.

Sample Path

The shipped sample lives under com.myriad.gateway.sdk.android.peakpay.

It demonstrates:

  • GatewayAndroidApp as the primary runtime surface
  • referencehost as optional managed-host tooling layered on top
  • device-management payloads built from SDK-collected Android metadata with optional app overrides

Consumer Smoke Target

In addition to the sample, gateway-sdk-android ships a consumer-path smoke target that models what a downstream monorepo POS app would look like when adopting the published artifact:

  • source: sdks/kotlin/gateway-sdk-android/src/consumerSmoke
  • tests: sdks/kotlin/gateway-sdk-android/src/consumerSmokeTest
  • Bazel targets: //sdks/kotlin/gateway-sdk-android:consumer-smoke and //sdks/kotlin/gateway-sdk-android:consumer-smoke-test

This module depends only on :gateway-sdk-android (the same artifact we publish), does not depend on soft-pos-sdk, and does not import anything from the smartconnect or host.internal packages. If a public-surface rename accidentally leaks an internal type onto an app-facing API, the consumer smoke target stops compiling in CI.

Consumer smoke covers the three documented adoption paths:

  1. HTTP-only client via GatewayAndroidClient / GatewayAndroidConfig.
  2. Embedded terminal runtime via GatewayAndroidApp.withDeviceRuntime.
  3. Managed host / device-management via GatewayAndroidReferenceHost.withRootKeySource.

Run it locally with bazel test //sdks/kotlin/gateway-sdk-android:consumer-smoke-test.

Release Wiring

The Android SDK ships from a single workflow, sdk-publish.yml. A release lands artifacts in two places:

DestinationWhat goes thereVersion resolution
Google Artifact Registry (us-east1-maven.pkg.dev/pinpoint-gateway/gateway-maven)gateway-sdk-android-{VERSION}.aar + POM and gateway-sdk-core-{VERSION}.jar + POM (plus the internal shared libs)Git tag on HEAD → SDK_VERSION_OVERRIDE → fallback in sdks/kotlin/publishing/version.bzl
GitHub Release assetsgateway-sdk-android-{VERSION}.aar + .pom, gateway-sdk-core-{VERSION}.jar + .pom, peak-pay-sample-android-{VERSION}.zip, plus iOS equivalentsSame resolution. POMs are rewritten with the resolved version before attach so they match what Artifact Registry served.

Consumers using Gradle (with rules_jvm_external or the standard Gradle dependency block) against Artifact Registry get the Maven-standard AAR layout and can resolve the full dependency closure (Android depends on core at the same version). Consumers pulling from the GitHub Release get the exact same closure in a single download — no separate Artifact Registry auth required for bring-up.

The artifact shape is considered final for 0.2.x:

  • Maven coordinates: com.myriad.gateway:gateway-sdk-android and com.myriad.gateway:gateway-sdk-core.
  • gateway-sdk-android is an AAR (Android Archive). The POM declares <packaging>aar</packaging>. AGP and Gradle resolve .aar coordinates automatically when this packaging type is present.
  • gateway-sdk-core remains a plain JVM jar (<packaging>jar</packaging>) for the 0.2.x release lane. The intended follow-on is to convert it to the shared KMP API-client layer that the iOS Swift package can consume as an XCFramework or SwiftPM wrapper, while keeping the Android terminal runtime in the AAR.
  • No Maven classifier, no sources jars in the release bundle.

Ownership Boundaries

This SDK draws a sharp boundary between what gateway owns and what the monorepo POS app owns. Treat the table below as the single source of truth when adding a new capability.

AreaGateway owns (this SDK / server)Monorepo POS app owns
Payment runtimeCard-present runtime, SmartConnect transport, pending-operation recovery, post-approval server replayCart model, receipt rendering, tender selection UI
Device enrollmentRegistration/heartbeat payloads, managed-host snapshot shaping, device-bound credential contractDevice identity persistence, operator-facing enrollment UX
Readiness / healthGatewayAndroidHostState, GatewayAndroidUiState, attention-level model, device-management capability inspectionMapping readiness → screen/banner placement, error retries at UI level
Attestation / device authOn-device credential shape, refresh/revocation state machine, (future) server issuance endpointsLifecycle ownership — when to call ensureValid, which operator triggers enrollment
Auth / credentialsOAuth client credentials, Firebase Auth token exchange, future device-bound credentialSecure storage of client secret + root key material, per-operator session
Recovery UX copyRecovery item dispositions, state machine, banner typesStrings, localization, screen flow
Card dataNever handled by app layerNever handled by app layer (SDK owns the wire)

Rules of thumb:

  • If a change affects wire format, network retry semantics, or the persistence of recovery/replay state, it belongs in the SDK.
  • If a change affects user-facing copy, navigation, or cross-feature orchestration (tax, split-tender, receipts), it belongs in the monorepo POS app.
  • If both sides need to change, the SDK lands the neutral contract first and the app adopts it — never the other way around.

Device-First Authorization Contract (Peak Pay)

Peak Pay is moving toward a device-first authorization model so that payment and device-management traffic is authenticated by an attested device credential rather than a bearer-token client secret. The SDK-side shape is stable today; the server side is still in progress.

What the SDK ships now

File: sdks/kotlin/gateway-sdk-android/src/main/kotlin/com/myriad/gateway/sdk/android/host/GatewayAndroidDeviceAuth.kt

Public types:

  • GatewayAndroidDeviceCredential — the on-device credential shape (token, attestation id, device id, issued/expires, optional refresh hint).
  • GatewayAndroidDeviceCredentialStateABSENT / VALID / REFRESH_DUE / EXPIRED / REVOKED.
  • GatewayAndroidDeviceCredentialSnapshot — snapshot the SDK hands to the app for UI/readiness binding.
  • GatewayAndroidDeviceCredentialSource — the pluggable surface through which the SDK obtains and refreshes credentials.
  • GatewayAndroidStaticDeviceCredentialSource — in-memory fixture-backed source for tests and pre-server-endpoint integration sprints.

Apps can bind GatewayAndroidDeviceCredentialSnapshot.state into the same readiness / capability surface they already use for GatewayAndroidHostState — REVOKED/EXPIRED stop payment just like an outstanding operator recovery does.

What the server still owes

The SDK-side contract is deliberately shipped ahead of the server work so the monorepo POS app has a stable binding surface. Before this carries real traffic, gateway still needs to land:

  1. Attestation mint endpoint — accepts Android-device attestation evidence and returns a signed, time-bound device credential.
  2. Attestation refresh endpoint — accepts an existing credential plus a device-signed proof-of-possession.
  3. Verifier on the processing/management Cloud Run services — translates an inbound Authorization: DeviceAttestation <token> header into the authenticated principal used downstream.
  4. Revocation path wired through device-management so that losing a device or disabling an operator invalidates outstanding credentials.

The kernel-specific attestation evidence and verification anchors continue to live in //sdks/kotlin/soft-pos-sdk. That module intentionally stays out of gateway-sdk-android's dependency graph. When the server work lands, gateway will ship a SoftPosDeviceCredentialSource implementation of GatewayAndroidDeviceCredentialSource inside soft-pos-sdk — app code continues to depend only on the Android SDK and does not need to follow the soft-pos-sdk release cadence.

API-key / OAuth coexistence

The device-first path is additive. API-key and OAuth client-credentials authentication remain supported on the Android SDK; the device credential is layered on top for card-present Peak Pay flows that the processor requires a device-bound token for. No deprecation of API keys is planned.