Applies to: Mobile Payments SDK - Android | Payments API | Orders API
Learn how to use the Mobile Payments SDK for Android to take a payment with a Square Reader.
Payments in the Mobile Payments SDK are handled by the PaymentManager. Prior to starting a payment, you create PaymentParameters to represent details of an individual payment and PromptParameters indicating how the payment prompts are presented to the buyer.
Before taking a payment with the SDK in a production environment, ensure that you have done the following:
- Requested the permissions necessary for the type of reader you're using.
- Installed and initialized the Mobile Payments SDK in your Android application.
- Authorized the Mobile Payments SDK with a Square account.
- Turned on the device's location services. The location permission alone isn't enough. Payments fail with
LOCATION_SERVICES_DISABLEDwhile services are off. - Confirmed the device clock is accurate. A skewed clock fails payments with
DEVICE_CLOCK_SKEWED. - Confirmed the payment amount uses the authorized location's currency. A mismatch fails with
USAGE_ERRORbefore the prompt appears. The examples on this page useCurrencyCode.USD.
Additionally, before taking a payment in production, you can test your application using mock readers and the Square Sandbox or download the Mobile Payments SDK sample application to see an example payment implementation.
To begin a payment with the Mobile Payments SDK, you need to create a PaymentParameters object, which includes attributes describing the payment you want to take. For example, there are parameters for the payment amount, optional tip, application fee (if applicable), and the processing mode, which determines whether payments can be taken offline. AUTO_DETECT is the recommended processingMode, as this directs the payment online or offline based on the highest chance of success. For this reason, the resulting Payment object might be an OnlinePayment or OfflinePayment, and your application should account for both if you're using the AUTO_DETECT processing mode. Merchants can optionally add card surcharges to payments, and your application can allow or override that setting with the allowCardSurcharge parameter.
val paymentParams = PaymentParameters.Builder( amount = Money(100, CurrencyCode.USD), processingMode = ProcessingMode.AUTO_DETECT, allowCardSurcharge = true, paymentAttemptId = UUID.randomUUID().toString() ) .build()
For the complete list of payment parameter values and details, see the Android technical reference.
Important
In Mobile Payments SDK version 2.2.0 and earlier, you supplied your own idempotencyKey in PaymentParameters. That parameter was deprecated in 2.3.0 and removed in 2.5.0. As of 2.4.0, paymentAttemptId is a required argument of the PaymentParameters.Builder constructor, and the SDK generates the idempotency key.
Square payment requests contain an idempotency key, a unique string identifier which allows Square to recognize potential duplicate API calls. Using an idempotency key for each payment request ensures that a payment can only occur once, protecting against unintended outcomes like charging a customer twice for the same transaction.
When you provide a paymentAttemptId in PaymentParameters, the Mobile Payments SDK generates an idempotency key for the payment request and stores it with your payment attempt ID. If multiple requests are required during one attempt, such as during Strong Customer Authentication (SCA), the SDK generates a new idempotency key for each request and updates the stored key for that attempt.
Along with a paymentAttemptId, include a referenceId in PaymentParameters to identify the payment in your system. Generate a unique paymentAttemptId for every attempt. If the SDK has already recorded the ID, the payment fails with USAGE_ERROR before the prompt appears. When retrying a declined payment, keep the same referenceId and generate a new paymentAttemptId.
If you don't receive a server response from a payment made with the Mobile Payments SDK, you should check its status to determine whether to attempt the payment again. Use the ListPayments endpoint and query by location ID, total payment amount, or other fields to filter the list. You can use your unique referenceId to identify the correct payment and check its status. You might need to make a new payment attempt if the prior payment exists, but cannot be completed. In this situation, call paymentManager.getIdempotencyKey(paymentAttemptId) and use the returned key with CancelPaymentByIdempotencyKey.
getIdempotencyKey returns Result<String?, PaymentErrorCode>. The SDK keeps keys for 24 hours and clears them when a different merchant authorizes the SDK. A missing key returns Success(null), so check for null and fall back to ListPayments with your referenceId.
Each payment also requires PromptParameters, consisting of a mode and a list of additionalPaymentMethods. PromptParameters.mode determines whether your application uses the DEFAULT Square payment prompt UI or a CUSTOM payment prompt where you build your own UI. The default UI provided by Square presents buyers with the payment options available from paymentManager.getAvailableCardEntryMethods(). While PaymentParameters are unique to each payment, you can likely reuse the same PromptParameters for most payments in your application.

PromptParameters.additionalPaymentMethods specifies a list of additional payment methods available to use for this payment. The current options are KEYED (a manually entered credit card payment) or CASH. When mode is PromptMode.DEFAULT, the Square payment prompt includes these alternative payment methods. If you supply your own UI with PromptMode.CUSTOM, use the additionalPaymentMethods available from PaymentHandle to display these options. A custom prompt replaces only the payment prompt screen; Square still displays manual card entry, cash entry, PIN entry, and payment status screens in its own Activity, and takes control once the buyer interacts with the card reader.
Important
With PromptMode.DEFAULT, the Square prompt collects data privacy consent. With PromptMode.CUSTOM, your application must collect it first and record the seller's choice with settingsManager.updateTrackingConsent(granted: Boolean). Where consent is required, starting a payment before the seller grants or denies it fails with CONSENT_NOT_PROVIDED. See Data privacy consent.
Begin processing a payment by calling paymentManager.startPaymentActivity() with the PaymentParameters and PromptParameters you created and a callback. The callback is invoked once on the main thread with the payment result or an error.
During the payment:
- The SDK provides a
PaymentHandleas a way for you to interact with the ongoing payment (for example, if you need to cancel the payment). - With
PromptMode.DEFAULT, Square takes control of the screen immediately by launching an Android Activity. WithPromptMode.CUSTOM, your prompt stays visible until the buyer interacts with the card reader.
When the payment completes, successfully or not, control returns to your user interface and your application can display receipt or error information to the user.
Note
Only one payment can be in process at a time. If you make a second call to startPaymentActivity before the first call completes, the second call fails immediately with a USAGE_ERROR, triggering the payment callbacks. The first payment call continues.
fun startPaymentActivity() { val paymentManager = MobilePaymentsSdk.paymentManager() val paymentAttemptId = UUID.randomUUID().toString() // Configure the payment parameters val paymentParams = PaymentParameters.Builder( amount = Money(100, CurrencyCode.USD), processingMode = ProcessingMode.AUTO_DETECT, allowCardSurcharge = true, paymentAttemptId = paymentAttemptId ) .referenceId("1234") .note("Chocolate Cookies and Lemonade") .autocomplete(true) .build() // Configure the prompt parameters val promptParams = PromptParameters( mode = PromptMode.DEFAULT, additionalPaymentMethods = listOf(AdditionalPaymentMethod .Type.KEYED) ) // Start the payment activity paymentHandle = paymentManager.startPaymentActivity(paymentParams, promptParams) { result -> // Handle the payment result when (result) { is Result.Success -> { val payment = result.value // Update your UI with the payment details. } is Result.Failure -> { val errorMessage = result.errorMessage // Update your UI with the payment error. } } } } override fun onDestroy() { paymentHandle?.cancel() super.onDestroy() }
As part of your application workflow, you might want to authorize a customer's transaction but delay the capture of the payment (the transfer of funds from the customer to the seller) for a period of time. For example, in a restaurant with a kiosk ordering system, you might want to authorize a customer's credit card when they order, but not complete the payment until they receive their food.
While creating PaymentParameters for a payment, set the autocomplete value to false if you want to delay the capture of a payment. By default, autocomplete is true, meaning the payment is authorized and captured immediately. When autocomplete is false, the payment is held in an approved state until explicitly completed or canceled.
Note
Only one of the autocomplete and acceptPartialAuthorization values can be true. If you're accepting multiple payment methods for a single purchase (such as a gift card and credit card), you must set autocomplete to false and manage the delayed capture of the payment.
When autocomplete is false, there are two more PaymentParameter values that handle the delayed payment:
delayDuration- ALongnumber of milliseconds to wait before taking thedelayAction. The SDK truncates the value to whole minutes and sends values under one minute as one minute. The default is 36 hours for card-present payments and 7 days for card-not-present payments, such as manually entered payments.delayAction- The action to take after thedelayDurationpasses with no other action on the payment. The possible options areCANCEL(which is the default) orCOMPLETE.
Note
delayDuration and delayAction are ignored when autocomplete is true or for non-card payments.
You can add a tip to the delayed payment by calling the UpdatePayment endpoint and setting tip_money prior to completing the payment. If you don't set the delayAction to automatically complete the payment, you can manually complete it by calling paymentManager.completePayment.
For more information about delayed payment capture using the Square Payments API, see Delayed Capture of a Card Payment.
A surcharge is an additional amount or percentage that sellers can set to pass on credit card processing fees to buyers. Sellers optionally set a surcharge percentage in their Square Dashboard. As a Mobile Payments SDK developer, you can include this surcharge or choose to override the dashboard settings and disallow surcharges on card payments in your application.
Important
- Surcharges with the Mobile Payments SDK are only available for credit card payments made in the US.
- Surcharges are not available for offline payments, debit card payments, or pre-existing orders.
- Square must enable card surcharging for the seller account. Contact
[email protected]to request enablement. - The seller must also set up card surcharges in their Square Dashboard for the payment location. Their setup can cover all locations or only selected ones.
- If either step is missing,
allowCardSurcharge = truehas no effect,PaymentHandle.totalMoneyWithProposedCardSurchargeisnull, and the SDK doesn't return an error.
To add surcharges to credit card payments, your application must have ITEMS_READ permission in addition to the standard payment permissions.
Use the allowCardSurcharge parameter in your PaymentParameters to control whether surcharges can be applied to individual payments.
If you're using a custom payment prompt, read the nullable PaymentHandle.totalMoneyWithProposedCardSurcharge to show buyers the total they will be charged, including the base amount, tip, proposed surcharge, and surcharge tax. If the value is null, no surcharge applies; show your amount-plus-tip total instead.
After an Online payment completes, access surcharge information from its CardPaymentDetails for receipt generation and record keeping:
private fun handlePaymentResult(result: Result<Payment, PaymentErrorCode>) { when (result) { is Result.Success -> { val payment = result.value if (payment is Payment.OnlinePayment) { val cardDetails = payment.cardDetails val surchargeDetails = cardDetails?.appliedCardSurchargeDetails if (surchargeDetails != null) { val baseSurcharge = surchargeDetails.cardSurchargeMoney val taxOnSurcharge = surchargeDetails.taxOnSurchargeMoney val totalSurcharge = surchargeDetails.totalSurchargeMoney // Display surcharge information to customer println("Base surcharge: ${baseSurcharge.amount} ${baseSurcharge.currencyCode}") println("Tax on surcharge: ${taxOnSurcharge?.amount ?: 0} ${baseSurcharge.currencyCode}") println("Total surcharge: ${totalSurcharge.amount} ${totalSurcharge.currencyCode}") // Use for receipt generation generateReceiptWithSurcharge(payment, surchargeDetails) } else { // No surcharge was applied to this payment generateStandardReceipt(payment) } } } is Result.Failure -> { // Handle payment errors handlePaymentError(result.errorCode) } } }
If you need to cancel a payment in progress for any reason, use paymentHandle.cancel(). The CancelResult returned is CANCELED, NO_PAYMENT_IN_PROGRESS if there is no payment in progress to be canceled, or NOT_CANCELABLE if the payment in progress cannot be canceled. This can happen when the payment is actively being sent to Square servers or has already been completed.
If the application is backgrounded or interrupted while the payment can still be canceled, the SDK cancels it. Once the payment has been sent to Square, backgrounding doesn't stop it and the callback still receives the final result.
Your application must provide buyers with the option to receive a digital or printed receipt. These receipts aren't sent directly by Square. Therefore, to remain compliant with EMV-certification requirements, you must generate receipts including the following fields found in the cardDetails of the successful payment response object from startPaymentActivity():
card.cardholderName(example: James Smith)card.brandandcard.lastFourDigits(example: Visa 0094)authorizationCode(example: Authorization 262921) (not available for offline payments)applicationName(example: AMERICAN EXPRESS)applicationId(example: AID: A0 00 00 00 25 01 09 01)entryMethod(example: Contactless)
private fun showPaymentDetails(payment: Payment, receiptScreen: ReceiptScreen) { // cardDetails is null for non-card payments, such as cash. val cardDetails = payment.cardDetails ?: return val card = cardDetails.card receiptScreen.setCardInformation( card.cardholderName, card.brand, card.lastFourDigits ) receiptScreen.setEntryMethod(cardDetails.entryMethod) when (cardDetails) { is CardPaymentDetails.OnlineCardPaymentDetails -> receiptScreen.setEmvInformation( cardDetails.authorizationCode, cardDetails.applicationName, cardDetails.applicationId ) is CardPaymentDetails.OfflineCardPaymentDetails -> receiptScreen.setEmvInformation( null, cardDetails.applicationName, cardDetails.applicationId ) } }