Applies to: In-App Payments SDK - Android | In-App Payments SDK - iOS | Payments API | Cards API
Learn how to start an SCA buyer verification, get the resulting verification token, and complete a payment.
Applies to: In-App Payments SDK - Android | In-App Payments SDK - iOS | Payments API | Cards API
Learn how to start an SCA buyer verification, get the resulting verification token, and complete a payment.
The In-App Payment SDK supports the Strong Customer Authentication (SCA) buyer verification flow for transactions where the buyer is present. When a buyer uses a payment card issued in a region that requires SCA, the issuing bank might require your In-App Payments SDK application to challenge the buyer for additional identifying information. This can happen in a one-time charge when a card is stored on file with Square or when a stored card is used in a transaction.
Complete the following steps to add the SCA flow to your application. The In-App Payments SDK handles all the buyer verification logic and the verification UI. You provide the location ID, buyer contact name, and payment ID (the payment token or stored customer payment card ID) to the buyer verification method and the SDK completes the SCA flow to return a verification token to your application.
Complete the steps in Build on iOS.
Install with CocoaPods by adding the following to your Podfile:
use_frameworks!
pod "SquareInAppPaymentsSDK"
pod "SquareBuyerVerificationSDK" ## Optional
SquareBuyerVerificationSDK
SDK to your project:Create a SQIPVerificationParameters object to encapsulate the information in the following list:
SQIPContact - You should build the SQIPContact
object with as many contact field values as possible, including givenName
, familyName
, and city
. The more complete the contact object, the lower the chance that the buyer is challenged by the card-issuing bank.
Payment source ID - This ID can be the payment token returned by the CardEntry
view controller or a card-on-file ID for the buyer's payment card stored with Square.
Location ID - The location IDs are found on the Locations page for your application in the Developer Console. The ID references a seller location and stores the physical address of the seller.
Buyer action - The buyer's intention of storing the card on file or charging it.
Pass it into the In-App-Payments SDK buyer verify method in step 3.
Create a SQIPTheme. You must provide a theme to style the verification challenge controller that SQIPBuyerVerificationSDK
starts if the card-issuing bank needs to get more identifying information from the buyer. To learn more about creating a theme, see Customize the Payment Entry Form.
func makeVerificationParameters(paymentSourceID: String, buyerAction: SQIPBuyerAction) -> SQIPVerificationParameters {
let contact = SQIPContact()
contact.givenName = "John"
contact.familyName = "Doe"
contact.email = "[email protected]"
contact.addressLines = ["London Eye","Riverside Walk"]
contact.city = "London"
contact.country = .GB
contact.postalCode = "SE1 7"
contact.phone = "8001234567"
return SQIPVerificationParameters(
paymentSourceID: paymentSourceID,
buyerAction: buyerAction,
locationID: VERIFY_BUYER_LOCATION_ID,
contact: contact
)
}
func makeSquareTheme() -> SQIPTheme{
let theme = SQIPTheme()
theme.errorColor = .red
theme.tintColor = Color.primaryAction
theme.keyboardAppearance = .light
theme.messageColor = Color.descriptionFont
return theme
}
SCA should be called for all customer-initiated transactions, including digital wallet payments. If the seller doesn't have SCA called for digital wallet payments, the transactions might be declined due to lack of authentication.
Complete this step if your application stores a buyer's payment card after the buyer enters the card information in the card entry view controller.
If your application uses Apple Pay, the verify
function should be called in the paymentAuthorizationViewControllerDidFinish
method (and not in the didAuthorizePayment
method) after the buyer dismisses Apple Wallet. Buyer verification won't occur if the Apple Wallet overlay is being displayed.
In this example, note the following:
buyerAction: .store()
.success
completion handler of the verify
function.extension MainViewController: SQIPCardEntryViewControllerDelegate {
func cardEntryViewController(
_ cardEntryViewController: SQIPCardEntryViewController,
didObtain cardDetails: SQIPCardDetails,
completionHandler: @escaping (Error?) -> Void) {
let params = makeVerificationParameters(
paymentSourceID: cardDetails.nonce,
buyerAction: .store(), //1: set buyer action to store
)
SQIPBuyerVerificationSDK.shared.verify(
with: params,
theme: makeSquareTheme(),
viewController: cardEntryViewController,
success: { (details) in //2: verification token available
storeCard(
nonce: cardDetails.nonce,
customerID: CUSTOMER_ID,
verificationToken: details.verificationToken,
completionHandler: completionHandler
)
},
failure: { error in
// Stop Square card entry UI spinner and display error message.
completionHandler(error)
}
)
}
//3: Print cURL command that stores the customer card on file
func storeCard(
nonce: String,
customerID: String,
verificationToken: String,
completionHandler: @escaping (Error?) -> Void) {
let uuid = UUID().uuidString
print("curl --request POST https://connect.squareup.com/v2/customers/{customerID}/cards \\" +
"--header \"Content-Type: application/json\" \\" +
"--header \"Authorization: Bearer YOUR_ACCESS_TOKEN\" \\" +
"--header \"Accept: application/json\" \\" +
"--data \'{" +
"\"idempotency_key\": \"\(uuid)\"," +
"\"card_nonce\": \"\(nonce)\"," +
"\"billing_address\": {" +
"\"address_line_1\": \"London Eye\"," +
"\"address_line_2\": \"Riverside Walk\"," +
"\"locality\": \"London\"," +
"\"postal_code\": \"SE1 7\"," +
"\"country\": \"UK\"}," +
"\"cardholder_name\": \"John Doe\"" +
"}\'");
// Call Square card entry completion handler to stop the
// UI spinner and indicate that the transaction was successful.
completionHandler(nil)
}
}
For information about storing a customer card on file after the payment token has been verified, see Manage cards on file.
In production, the CreateCard
and CreatePayment
operations are run on your backend after your client provides the payment token and verification token.
Verify the buyer payment card and send the resulting verification token and the payment source ID (the payment token or stored customer payment card ID) to your backend to complete a payment with verification.
In this example, note the following:
buyerAction: .charge(SQIPMoney)
.success
completion handler of the verify
function.extension PurchaseController {
func checkout(paymentSourceID: String, purchaseAmount: SQIPMoney) {
let params = makeVerificationParameters(
paymentSourceID: paymentSourceID,
buyerAction: .charge(purchaseAmount) //1: Set buyer action to charge
)
SQIPBuyerVerificationSDK.shared.verify(
with: params,
theme: makeSquareTheme(),
viewController: self,
success: { (details) in //2: Verification token available
// Send payment request to your backend with token here.
processPayment(
paymentSourceID: paymentSourceID,
verificationToken: details.verificationToken,
purchaseAmount: purchaseAmount,
successHandler: {
print("Successfully processed payment")
},
errorHandler: { error in
print(error.localizedDescription)
}
)
},
failure: { error in
// Unable to verify buyer identity. Handle error.
})
}
// 3: Print cURL command that completes a payment with verfied payment source
func processPayment(
paymentSourceID: String,
verificationToken: String,
purchaseAmount: SQIPMoney,
successHandler: (Void) -> Void,
errorHandler: (Error) -> Void
) {
let uuid = UUID().uuidString
print(
"curl --request POST https://connect.squareup.com/v2/payments \\"
+ "--header \"Content-Type: application/json\" \\"
+ "--header \"Authorization: Bearer YOUR_ACCESS_TOKEN\" \\"
+ "--header \"Accept: application/json\" \\" + "--data \'{"
+ "\"idempotency_key\": \"\(uuid)\"," + "\"autocomplete\": true," + "\"amount_money\": {"
+ "\"amount\": \(purchaseAmount.amount)," + "\"currency\":\"\(purchaseAmount.currency)\"},"
+ "\"verification_token\": \"\(verificationToken)\","
+ "\"source_id\": \"\(paymentSourceID)\"" + "}\'")
successHandler()
}
}
If you need more assistance, contact Developer and App Marketplace Support or ask for help in the Developer Forums.