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.
| Item | Value |
|---|---|
| Maven coordinate | com.synaptopay:synapto-pos-android |
| Package | com.synaptopay.pos |
| Entry point | SynaptoPos |
| Minimum Android API | 23 |
| Java bytecode | Java 11 |
| Softpay AppSwitch dependency | io.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)| Parameter | Meaning |
|---|---|
context | Any Android context. The SDK keeps only its application context. |
publishableKey | The 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 prefix | Synapto API | Companion app package |
|---|---|---|
pk_sandbox_ | https://api.synaptopay-sandbox.com | io.softpay.sandbox |
pk_live_ | https://api.synaptopay.com | io.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.
TapToPayStatus | Next step |
|---|---|
COMPANION_APP_MISSING | Install the companion app for this environment, then check again. |
COMPANION_APP_UPDATE_REQUIRED | Update the companion app, then check again. |
SETUP_REQUIRED | Complete pairing. |
READY | The 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
)| Parameter | Meaning |
|---|---|
activity | The current resumed Activity. The SDK uses it to open the companion app. |
pairingToken | The setup_token from your POS Backend's pairing response. One use only. |
pairingReference | The pairing.name from the same response. Pass it unchanged. |
callback | Receives 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.
PairingStatus | Meaning |
|---|---|
PENDING | Synapto has not recorded an outcome. |
FAILED | Synapto recorded a failed pairing. |
SUCCEEDED | Synapto 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
)| Parameter | Meaning |
|---|---|
clientSecret | The client_secret of the Payment Intent your POS Backend created for this sale. |
callback | Receives 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.
PaymentStatus | Meaning |
|---|---|
SUCCEEDED | Synapto recorded a successful payment. Your POS Backend confirms the sale independently; see Confirm the sale on your server. |
DECLINED | The card was declined. The merchant may retry or take another payment method. |
CANCELED | The payment attempt or the Payment Intent was canceled. Closing a handle does not produce this status. |
FAILED | The attempt failed for a reason other than decline or cancellation. |
PROCESSING | No 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.
| Callback | Result | Outcome accessors | Error type |
|---|---|---|---|
TapToPayStatusCallback | TapToPayStatusResult | hasStatus(), getStatus() | ReadinessError |
PairingCallback | PairingResult | hasOutcome(), getOutcome() | PairingError |
PairingStatusCallback | PairingStatusResult | hasStatus(), getStatus() | PairingError |
PaymentCallback | PaymentResult | hasStatus(), 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
| Value | Next step |
|---|---|
CONFIGURATION_ERROR | Check the publishable key and environment. If they are correct, contact Synapto. Do not start a new pairing. |
SERVICE_UNAVAILABLE | Synapto or the companion app was unreachable or busy, or the check timed out. Check again later. |
UNEXPECTED | The SDK could not determine readiness. Log the diagnostic message and contact Synapto if it repeats. |
PairingError
| Value | Next step |
|---|---|
INVALID_CONFIGURATION | Check the publishable key. |
INVALID_PAIRING_CONTEXT | The 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_UNAVAILABLE | Synapto 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. |
UNEXPECTED | Log 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.
| Value | Next step |
|---|---|
COMPANION_APP_MISSING | Install the companion app. |
COMPANION_APP_UPDATE_REQUIRED | Update the companion app. |
SETUP_REQUIRED | No paired terminal can take this payment. Complete pairing. |
RELEASE_REQUIRED | The 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_CONFIGURATION | Check the publishable key. |
INVALID_PAYMENT_CONTEXT | The client secret is invalid or belongs to another account. Retrieve the original client secret from your POS Backend. |
CONFIGURATION_ERROR | Check the publishable key and environment. If they are correct, contact Synapto. |
SERVICE_UNAVAILABLE | The readiness check or status read did not complete. Keep the sale open and read again. |
UNEXPECTED | Log 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.
| Exception | Cause |
|---|---|
IllegalArgumentException | Invalid context or key; finishing or destroyed Activity; blank token or client secret; malformed pairing reference. |
NullPointerException | Null callback. |
IllegalStateException | SDK 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:
| Operation | Rule |
|---|---|
| Readiness check | One at a time. Rejected while a payment is active. |
| Pairing wait | One at a time. Rejected while a payment is active. |
| Payment | One at a time. Rejected while a readiness check or pairing wait is active. |
| Pairing or payment status read | Allowed 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.
Updated 22 days ago