Android POS SDK

Android POS SDK

The Synapto POS SDK for Android lets your Android point-of-sale app accept Tap to Pay payments on the merchant's phone.

This page uses these terms:

  • POS App: your Android app. It calls the SDK.
  • POS Backend: your server. It holds your secret API key and calls the Synapto server API.
  • Softpay: the third-party provider Synapto uses for Tap to Pay.
  • Companion app: the Softpay Android app that accepts the contactless card. It is installed separately on the merchant's phone. The SDK opens it for setup and for each payment.
  • Pairing: the one-time link between a Tap to Pay terminal, a resource Synapto provisions for the account, and the companion app installation.

Your POS App calls only the Synapto SDK. It does not call Softpay APIs. For the integration sequence, start with Tap to Pay Setup, then Tap to Pay Payments. Those guides include Kotlin and Java examples for every method below.

Installation and compatibility

Contact Synapto to obtain the SDK. For initial integrations, Synapto sends a bundled Maven repository by email or download link. Keep its directory structure and use the version and Gradle configuration supplied with it. Do not copy only the AAR into libs/: the SDK depends on the Softpay AppSwitch library, which the bundle also contains.

ItemValue
Maven coordinatecom.synaptopay:synapto-pos-android
Packagecom.synaptopay.pos
Entry pointSynaptoPos
Minimum Android API23
Java bytecodeJava 11
Softpay AppSwitch dependencyio.softpay:softpay-client:1.9.0

The SDK adds the INTERNET permission and package-visibility entries for the companion app. It adds no Activity, service, or dangerous permission.

The minimum API level does not mean every device can take payments. Ask Synapto for the supported device list and test on a supported physical device.

Initialization

public static void initialize(Context context, String publishableKey)
ParameterMeaning
contextAny Android context. The SDK keeps only its application context.
publishableKeyThe publishable key of the account the merchant is signed in to. Never pass a secret API key.

Call once, before any other SDK method. Initialization is synchronous. It does no network work and does not validate the key. Calling it again with the same key does nothing.

The key prefix selects the Synapto environment and the companion app. There is no separate environment option.

Key prefixSynapto APICompanion app package
pk_sandbox_https://api.synaptopay-sandbox.comio.softpay.sandbox
pk_live_https://api.synaptopay.comio.softpay

Your POS Backend obtains the key; see Setup. One process serves one account at a time. See Account switching before initializing with a different key.

Readiness

public static OperationHandle getTapToPayStatus(TapToPayStatusCallback callback)

Runs one readiness check and returns a TapToPayStatusResult. The check has a 30-second deadline. It is not a subscription.

TapToPayStatusNext step
COMPANION_APP_MISSINGInstall the companion app for this environment, then check again.
COMPANION_APP_UPDATE_REQUIREDUpdate the companion app, then check again.
SETUP_REQUIREDComplete pairing.
READYThe companion app is set up. A payment can still return SETUP_REQUIRED or RELEASE_REQUIRED if the installation does not match the pairing Synapto holds for the account.

Pairing

startPairing

public static PairingWait startPairing(
    Activity activity,
    String pairingToken,
    String pairingReference,
    PairingCallback callback
)
ParameterMeaning
activityThe current resumed Activity. The SDK uses it to open the companion app.
pairingTokenThe setup_token from your POS Backend's pairing response. One use only.
pairingReferenceThe pairing.name from the same response. Pass it unchanged.
callbackReceives one PairingResult.

The SDK first reads the pairing from Synapto. If the pairing is already final, the callback receives that outcome and the companion app does not open. If the pairing has expired, the callback receives INVALID_PAIRING_CONTEXT. Otherwise the SDK opens the companion app and polls Synapto until Synapto records an outcome.

The wait has no timeout. The SDK retries temporary service failures with increasing delays. Repeated server errors end the wait with UNEXPECTED.

The SDK holds the Activity weakly until the companion app opens. If the Activity is not resumed at that moment, the callback receives SERVICE_UNAVAILABLE. After the companion app opens, Activity recreation and backgrounding do not stop the wait. Your Activity resuming does not mean pairing finished.

Treat the token as opaque. Do not parse it, and do not build the Softpay setup intent yourself.

getPairingStatus

public static OperationHandle getPairingStatus(
    String pairingReference,
    PairingStatusCallback callback
)

Reads the pairing once and returns a PairingStatusResult. It does not open the companion app. Use it after process death or reinstall, with the reference stored on your POS Backend.

PairingStatusMeaning
PENDINGSynapto has not recorded an outcome.
FAILEDSynapto recorded a failed pairing.
SUCCEEDEDSynapto recorded a successful pairing. Run a readiness check before enabling payments.

PairingOutcome, delivered by startPairing, has only FAILED and SUCCEEDED. A PairingError means the SDK could not complete the operation. It does not mean pairing failed.

Payments

processPayment

public static OperationHandle processPayment(
    String clientSecret,
    PaymentCallback callback
)
ParameterMeaning
clientSecretThe client_secret of the Payment Intent your POS Backend created for this sale.
callbackReceives one PaymentResult. It does not stream progress.

The SDK runs a readiness check, then asks Synapto to authorize the attempt. If Synapto authorizes a new attempt, the SDK opens the companion app for one payment at the Payment Intent's amount and currency. If an attempt is already pending, the callback receives PROCESSING and the companion app does not open.

The SDK waits for the companion app's result, then polls Synapto for a limited time. If no final result arrives, the callback receives PROCESSING. PROCESSING does not tell you whether the customer tapped a card. Never treat it, or a UI timeout, as permission to start another payment.

getPaymentStatus

public static OperationHandle getPaymentStatus(
    String clientSecret,
    PaymentCallback callback
)

Sends one status request to Synapto for the same client secret. It does not run a readiness check, open the companion app, or poll. Use it after PROCESSING, after closing a payment handle, or after process death. If the result is still PROCESSING, your app decides when to read again.

Before it opens the companion app, the SDK stores the Softpay request ID on the device under a hash of the client secret. It never stores the secret. A final result from Synapto clears the entry. Your POS Backend must still let the app retrieve the original client secret after a restart.

Payment statuses

These are SDK statuses, not Payment Intent states.

PaymentStatusMeaning
SUCCEEDEDSynapto recorded a successful payment. Your POS Backend confirms the sale independently; see Confirm the sale on your server.
DECLINEDThe card was declined. The merchant may retry or take another payment method.
CANCELEDThe payment attempt or the Payment Intent was canceled. Closing a handle does not produce this status.
FAILEDThe attempt failed for a reason other than decline or cancellation.
PROCESSINGNo final result yet. Keep the sale open and read the status again.

A Payment Intent with no attempt yet also reads as PROCESSING. See Safe retries before starting another attempt.

Results and callbacks

Every callback interface has one method, onComplete(result), and accepts a lambda in Kotlin and Java. The SDK delivers each result once, on the main thread.

CallbackResultOutcome accessorsError type
TapToPayStatusCallbackTapToPayStatusResulthasStatus(), getStatus()ReadinessError
PairingCallbackPairingResulthasOutcome(), getOutcome()PairingError
PairingStatusCallbackPairingStatusResulthasStatus(), getStatus()PairingError
PaymentCallbackPaymentResulthasStatus(), getStatus()PaymentError

Exactly one of the outcome and getError() is non-null. Check hasStatus() or hasOutcome() first.

Every result also has getDiagnosticMessage(). Its text is for your logs and for Synapto support. It can change between SDK versions. Do not branch on it or show it to customers.

Errors

An error means the SDK could not complete the operation. It is not a payment or pairing outcome.

ReadinessError

ValueNext step
CONFIGURATION_ERRORCheck the publishable key and environment. If they are correct, contact Synapto. Do not start a new pairing.
SERVICE_UNAVAILABLESynapto or the companion app was unreachable or busy, or the check timed out. Check again later.
UNEXPECTEDThe SDK could not determine readiness. Log the diagnostic message and contact Synapto if it repeats.

PairingError

ValueNext step
INVALID_CONFIGURATIONCheck the publishable key.
INVALID_PAIRING_CONTEXTThe pairing is missing, expired, or belongs to another account. Fetch the pairing reference from your POS Backend and read its status before requesting a new pairing.
SERVICE_UNAVAILABLESynapto was unreachable, or the companion app could not open because the Activity was not resumed or the app is not installed. Follow Recover or retry pairing.
UNEXPECTEDLog the diagnostic message. Read the pairing status and contact Synapto if it repeats.

PaymentError

An error from getPaymentStatus does not mean the payment failed. Keep the sale open and read again.

ValueNext step
COMPANION_APP_MISSINGInstall the companion app.
COMPANION_APP_UPDATE_REQUIREDUpdate the companion app.
SETUP_REQUIREDNo paired terminal can take this payment. Complete pairing.
RELEASE_REQUIREDThe companion app installation no longer matches the pairing Synapto holds. Contact Synapto to release the pairing, then pair again. Do not request new pairings until Synapto confirms the release.
INVALID_CONFIGURATIONCheck the publishable key.
INVALID_PAYMENT_CONTEXTThe client secret is invalid or belongs to another account. Retrieve the original client secret from your POS Backend.
CONFIGURATION_ERRORCheck the publishable key and environment. If they are correct, contact Synapto.
SERVICE_UNAVAILABLEThe readiness check or status read did not complete. Keep the sale open and read again.
UNEXPECTEDLog the diagnostic message. Keep the sale open and read again.

Synchronous exceptions

Invalid arguments and conflicting calls throw before the SDK accepts the call. These never arrive through a callback. They are not payment outcomes and must not start another payment.

ExceptionCause
IllegalArgumentExceptionInvalid context or key; finishing or destroyed Activity; blank token or client secret; malformed pairing reference.
NullPointerExceptionNull callback.
IllegalStateExceptionSDK not initialized; a conflicting operation is active; account switch during active work.

Handles and concurrency

Every asynchronous method returns an OperationHandle. startPairing returns its subtype PairingWait. Both implement AutoCloseable.

Keep the handle while you want the result. Do not wrap it in try-with-resources or Kotlin use. Do not close a handle because the Activity paused: the companion app opening in front of your app is part of the flow.

close() stops the SDK from delivering the result to your callback. It does not cancel pairing or payment, does not clear the stored request ID, and does not interrupt an HTTP request in flight. A pairing result that is already queued for delivery still arrives after close().

Keep handles, results, and callbacks in an object that outlives the Activity, for example a ViewModel. The callback updates that object's state. The current screen observes the state and re-renders it after recreation. A callback must not hold a reference to a destroyed Activity.

The SDK allows one operation of each kind per process:

OperationRule
Readiness checkOne at a time. Rejected while a payment is active.
Pairing waitOne at a time. Rejected while a payment is active.
PaymentOne at a time. Rejected while a readiness check or pairing wait is active.
Pairing or payment status readAllowed during other work. Each call is one read.

Run readiness, pairing, and payment in sequence, as the guides show.

Account switching

Initialize with a different key only when no SDK work is active. The SDK rejects the switch during a readiness check, a pairing wait, a payment, or a payment status read. Let them finish or close their handles first. A pairing result that is queued for delivery must arrive before the switch succeeds.

Before switching, detach the old screen's observers so results for the previous account are not shown in the new session. After switching, fetch the new account's pairing reference and client secrets from your POS Backend. Never reuse the previous account's values. Keep any unresolved sale for the previous account on your POS Backend.


Did this page help you?