Kotlin SDK
Android consumers use the self-contained gateway-sdk-android AAR instead
of adding core artifacts alongside it; duplicate classes are not a supported
installation. The optional NearPay AAR is additive only for that rail.
Clients and authentication
GatewayPayClient owns payment-facing operations and GatewayAdminClient
organization administration. Both use GatewayConfig and suspend APIs.
Machine client credentials belong on a trusted backend, not in a distributed
app. Mobile apps should obtain an authorized token from their backend; managed
terminal enrollment uses the Android SDK.
import com.myriad.gateway.Environment
import com.myriad.gateway.GatewayConfig
import com.myriad.gateway.GatewayPayClient
val pay = GatewayPayClient(
GatewayConfig(
clientId = clientId,
clientSecret = clientSecret,
environment = Environment.STAGING,
),
)
// Use pay for authorized payment work; close it when its owner shuts down.
SDK-managed OAuth caches and refreshes tokens. A pre-issued bearer token uses
accessToken; its issuing layer owns validity. See
Authentication and
Organizations and Locations
for scopes and tenant selection.
Integration choices
- Hosted checkout for Gateway-hosted card entry.
- Android managed runtime for embedded acceptance, or Bolt for a cloud-connected terminal.
- Wallets, gift cards, and tax for their respective consumer contracts.
- Webhook events for safe replay and delivery verification.
Use the SDK request types and API reference rather than constructing vendor requests. Monetary fields are integer minor units where named as amounts; tax rates use basis points.
Durable checkout creation
pay.checkoutSessions.create(request, idempotencyKey) requires a nonblank key
of at most 64 characters. Persist the key, original location and request before
dispatch. Recover a lost response with the authenticated
pay.checkoutSessions.getByKey(idempotencyKey, locationId) suspend operation.
It returns the existing session's current state without repricing or reopening it.
The authenticated organization, location and key form the durable identity.
The original request fingerprint is frozen: identical input replays before
mutable capability, policy and tax validation; changed input returns HTTP 409.
Only GatewayException.NotFoundError establishes absence at the lookup read,
not that a delayed original create cannot commit. Network, authorization and
contract failures do not establish absence. Any recovery retry must use the
original key and body; only a genuinely new business attempt uses a new
persisted identity.
For pre-cutover requests, the guarantee covers retained legacy successes only after verified adoption of their original session. Adoption freezes the current full typed body; the old sanitized hash cannot prove excluded original fields. Legacy in-progress entries fail closed, and purged legacy identities cannot be recovered by key alone. Rollout requires an in-flight census and fence; see existing identities at cutover.
Outcome handling
Distinguish explicit approval, explicit decline, and failure/unknown results. Catch the SDK's typed authentication, rate-limit, network, server, validation, and not-found errors. Network failure is not evidence that a payment was not executed. Preserve the operation identity and reconcile an indeterminate result before any authorized follow-on operation. Generic transport retries do not make non-idempotent terminal or payment commands safe to resubmit.
INTERNAL_STATE_ERROR is a server-side invariant failure (HTTP 500). The SDK
preserves its gatewayErrorCode on GatewayException.ServerError and does not
retry it, including raw responses and bounded sync attempts. Non-retryable does
not mean unexecuted: Android retains durable reconciliation evidence and requires
an authoritative lookup before acknowledging an uncertain recording, refund, or
reversal. Cancellation and recording redispatch remain blocked for that operation
across restart and recovery. SoftPOS sync and enrichment do not schedule another
automatic attempt. Genuine state conflicts remain HTTP 409.
Verify webhooks against the raw body with WebhookVerifier.verifyDelivery and
the signature/timestamp headers. Keep only safe event/reference/correlation IDs
in logs and handle duplicate delivery idempotently.
The decoded WebhookEvent has one variant per Gateway event type
(payment.completed → WebhookEvent.PaymentCompleted), holding the delivery
envelope and the event payload. An event type newer than the SDK decodes to
WebhookEvent.Unknown with the whole body in raw, so give every
when (event) an else or is WebhookEvent.Unknown branch.