Implement callbacks to customise your Paze payment flow for iOS.
The Paze component emits callbacks based on shopper interaction and payment flow state. Use them to inject business logic and UX customisations at critical moments. While the SDK handles checkout, decryption, and authorisation, you retain control over approval gates, error handling, and backend integration.
Callbacks enable you to:
- Validate business rules before payments proceed.
- Display custom error, failure, or success messages.
- Integrate with fraud detection or customer management systems.
- Control how shoppers experience successful and failed transactions.
- Handle Paze web checkout and decryption flow requirements.
Configure onGetShopper on CheckoutConfig when calling PxpCheckout.initialize(config:), not on the Paze button component. The SDK calls onGetShopper when building the Unity transaction request after decryption.
onGetShopper(recommended): Called during authorisation to retrieve shopper data for the transaction payload.onGetShippingAddress(optional onCheckoutConfig): Available for other checkout components, but not called by the Paze button during authorisation.
The SDK calls this callback when building the transaction request, after decryption and before Unity authorisation.
You can use it to:
- Provide a stable shopper ID for your customer account or guest session.
- Return the latest name, email, and contact details from your application.
- Associate the Paze network-token transaction with your customer records.
let checkoutConfig = CheckoutConfig(
environment: .test,
session: sessionData,
transactionData: transactionData,
merchantShopperId: "shopper-123",
ownerId: "owner-456",
onGetShopper: { async in
TransactionShopper(
id: "shopper-123",
firstName: "John",
lastName: "Doe",
email: "customer@example.com"
)
}
)
let pxpCheckout = try PxpCheckout.initialize(config: checkoutConfig)| Property | Description |
|---|---|
idString? | A unique shopper identifier. Return your customer account ID or a persistent guest session ID. |
firstNameString? | The shopper's given name. |
lastNameString? | The shopper's family name. |
emailString? | The shopper's email address. |
phoneNumberString? | The contact phone number for the transaction shopper profile. |
dateOfBirthString? | The date of birth, when required by your integration or risk screening rules. |
houseNumberOrNameString? | The first line of the shopper's address. |
streetString? | The street name or remaining address line. |
cityString? | The city or locality. |
postalCodeString? | The postal or ZIP code. |
countryCodeString? | The country code in ISO 3166-1 alpha-2 format (e.g., "US"). |
stateString? | The state, province, or region. |
products[String: String]? | Key-value metadata describing products in the order. |
orderDescriptionString? | A human-readable order description. |
All properties are optional in the type, but you should always return an id so transactions can be linked to your customer records.
onGetShopper: { async in
let customer = await getCurrentCustomer()
if let customer {
return TransactionShopper(
id: customer.id,
email: customer.email,
firstName: customer.firstName,
lastName: customer.lastName,
phoneNumber: customer.phone
)
}
return TransactionShopper(id: getOrCreateGuestShopperId())
}Paze wallet identity (emailAddress / phoneNumber on the component) is separate from onGetShopper. Component identity is passed to Paze during session creation when provided. onGetShopper supplies the shopper object sent to Unity during authorisation.
onGetShippingAddress is defined on CheckoutConfig for other payment flows (for example, card submit or drop-in). The Paze button component doesn't call it when building the authorisation request.
If you need shipping context for Paze, pass it through enhancedTransactionData.ecomData.finalShippingAddress on the component config instead. See Configuration.
Configure these callbacks on PazeButtonComponentConfig before calling create(.pazeButton, componentConfig:).
| Callback | SDK signature |
|---|---|
onInit | (() -> Void)? |
onPresentmentResolved | ((Bool) -> Void)? |
onError | ((BaseSdkException) -> Void)? |
onPazeButtonClicked | (() async -> Void)? |
onCheckoutComplete | ((PazeCheckoutResult) async -> Bool)? |
onCheckoutIncomplete | ((PazeCheckoutResult) async -> Void)? |
onComplete | ((PazeCompleteResult) async -> Void)? |
onPreDecryption | (() async -> Bool)? |
onPostDecryption | ((PazeDecryptTokenResponseSuccess) async -> Void)? |
onPreAuthorisation | (() async -> PazePreAuthorisationResult)? |
onPostAuthorisation | ((MerchantSubmitResult) async -> Void)? |
onSubmitError | ((BaseSubmitResult) async -> Void)? |
onGetShopper (CheckoutConfig) | (() async -> TransactionShopper?)? |
For a successful payment, callbacks fire in this order:
onInit→onPresentmentResolved(true)when the component view appears.onPazeButtonClickedwhen the shopper taps the button.onCheckoutCompleteoronCheckoutIncompleteafter the Paze web checkout session returns.onCompleteafter the complete API succeeds and the response is decoded.onPreDecryption→onPostDecryption(if SDK decryption proceeds).onPreAuthorisation→ Unity authorisation (the SDK callsonGetShopperhere) →onPostAuthorisationoronSubmitError.
onError handles presentment, checkout, complete, and decryption errors. onSubmitError handles authorisation submission failures, including invalid Kount riskScreeningData. Shopper cancellation is surfaced through onCheckoutIncomplete, not onError.
Configure onGetShopper on CheckoutConfig when calling PxpCheckout.initialize(config:). Paze component callbacks handle checkout, decryption, and authorisation events.
Called after presentment validation succeeds, immediately before onPresentmentResolved(true).
config.onInit = {
print("Paze component ready")
}Called when presentment resolves with whether the button is visible.
| Parameter | Description |
|---|---|
isVisibleBool | true when the button is shown, false when validation failed (see onError). |
config.onPresentmentResolved = { isVisible in
if !isVisible {
showAlternativePaymentMethods()
}
}Called when the shopper taps the button, before the Paze web checkout session opens. Use it for analytics, clearing error messages, or showing a loading state.
onPazeButtonClicked is a component callback. The PazeButtonClicked analytics event is separate — it fires only after checkout-time validation succeeds, immediately before the web session opens. See Analytics.
config.onPazeButtonClicked = { async in
clearErrorMessages()
trackEvent("paze_button_clicked")
}The SDK always opens the Paze checkout session after this callback completes. To block checkout when validation fails, keep the button disabled until your prerequisites are met, or return false from onCheckoutComplete after the shopper finishes in Paze.
Called when checkout returns COMPLETE, before the SDK calls the complete API.
Return true to approve and continue (default when omitted). Return false to reject. The SDK calls onCheckoutIncomplete.
| Parameter | Description |
|---|---|
resultPazeCheckoutResult | The checkout result data. |
result.resultenum | The result: .complete or .incomplete. |
result.checkoutResponseString? | The encoded checkout response JWT when complete. |
result.checkoutDecodedResponsePazeCheckoutDecoded? | The decoded consumer, session, and masked card data. |
result.checkoutDecodedResponse?.maskedCard?.panLastFourString | The last four digits of the selected card. |
result.checkoutDecodedResponse?.maskedCard?.paymentCardBrandString | The card brand returned by Paze (for example, VISA). |
result.checkoutDecodedResponse?.maskedCard?.paymentCardNetworkString | The card network returned by Paze. |
result.reasonString? | An optional reason from Paze. |
config.onCheckoutComplete = { result async in
guard let decoded = result.checkoutDecodedResponse else { return false }
let isValid = await validateCheckoutOnBackend(
sessionId: decoded.sessionId,
cardLastFour: decoded.maskedCard?.panLastFour
)
return isValid
}Called when checkout ends without completion, the shopper cancels, or you return false from onCheckoutComplete. When you reject in onCheckoutComplete, the reason is set from the SDK's localised merchant-validation message.
| Parameter | Description |
|---|---|
result.reasonString? | The reason for the incomplete checkout (e.g. "User cancelled."). |
config.onCheckoutIncomplete = { result async in
if result.reason == "User cancelled." {
return
}
showError("Checkout was not completed. Please try again.")
}Called when the complete API succeeds and the response is decoded. Runs before onPreDecryption.
Use result.completeDecodedResponse?.securedPayload for manual decryption when onPreDecryption returns false.
config.onComplete = { result async in
print("Payload ID:", result.completeDecodedResponse?.payloadId ?? "")
}Called after onComplete, before the SDK decrypts the secured payload.
Return true to allow SDK decryption (default when omitted). Return false to handle decryption on your backend.
config.onPreDecryption = { async in
let approved = await requestManagerApproval()
return approved
}Called after Unity successfully decrypts the network token. Fires when SDK decryption proceeds — including when onPreDecryption is omitted or returns true. Skipped when onPreDecryption returns false.
| Parameter | Description |
|---|---|
decryptedPayload.shopperobject | The customer name, email, and phone from the decrypt response. |
decryptedPayload.billingAddressobject? | The billing address when returned by Paze. |
decryptedPayload.fundingDataobject | The network token, expiry, card network, and related fields. |
config.onPostDecryption = { decrypted async in
print("Card network:", decrypted.fundingData.cardNetwork)
}Called before the transaction is submitted to Unity.
| Return value | Behaviour |
|---|---|
.proceed | Continue without extra data (default when omitted). |
.cancel | Abort authorisation. |
.transactionInitData(...) | Continue with risk screening or other init data. |
config.onPreAuthorisation = { async in
guard await validateOrderDetails() else {
return .cancel
}
return .transactionInitData(PazeTransactionInitData(
riskScreeningData: RiskScreeningData(
performRiskScreening: true,
userIp: await getUserIpAddress()
)
))
}Called when the SDK receives a MerchantSubmitResult, immediately before your callback runs. Verify the transaction outcome on your backend — the Unity response may report an error state while still returning transaction identifiers.
| Parameter | Description |
|---|---|
data.merchantTransactionIdString | Your transaction identifier. |
data.systemTransactionIdString | The system transaction identifier generated by PXP. |
config.onPostAuthorisation = { data async in
await verifyPaymentOnBackend(systemTransactionId: data.systemTransactionId)
navigateToOrderConfirmation(merchantTransactionId: data.merchantTransactionId)
}Called when authorisation submission fails, including invalid Kount riskScreeningData (ValidationException). Cast to FailedSubmitResult for error details.
config.onSubmitError = { result async in
if let failed = result as? FailedSubmitResult {
showError(failed.errorReason ?? "Payment failed")
}
}Called on presentment, checkout, complete, or decryption errors. Shopper cancellation is surfaced through onCheckoutIncomplete, not onError.
| Parameter | Description |
|---|---|
error.errorCodeString | The SDK error code (e.g. SDK1213). |
error.errorMessageString | A human-readable error message. |
config.onError = { error in
switch error.errorCode {
case "SDK0118":
showError("Paze isn't enabled for this session.")
case "SDK1213":
showError("Paze is only available for USD transactions.")
case "SDK1202":
showError("Paze client ID is missing from the session.")
case "SDK1202A":
showError("Paze merchant category code is missing from the session.")
case "SDK1214", "SDK1200":
showError("Paze checkout failed. Please try again.")
default:
showError(error.errorMessage)
}
}Returned by onGetShopper:
struct TransactionShopper {
var id: String?
var firstName: String?
var lastName: String?
var dateOfBirth: String?
var email: String?
var phoneNumber: String?
var houseNumberOrName: String?
var street: String?
var city: String?
var postalCode: String?
var countryCode: String?
var state: String?
var products: [String: String]?
var orderDescription: String?
}Defined on CheckoutConfig for other payment flows. Not used by the Paze button component.
struct ShippingAddress {
var countryCode: String?
var postalCode: String?
var address: String?
var addressLine2: String?
var city: String?
var county: String?
var state: String?
}Passed to onCheckoutComplete and onCheckoutIncomplete:
public struct PazeCheckoutResult {
var result: CheckoutResultType // PazeCheckoutResult.CheckoutResultType
var checkoutResponse: String?
var reason: String?
var checkoutDecodedResponse: PazeCheckoutDecoded?
}
public extension PazeCheckoutResult {
enum CheckoutResultType {
case complete // raw value "COMPLETE"
case incomplete // raw value "INCOMPLETE"
}
}checkoutDecodedResponse is populated when result is .complete.
Included on checkoutDecodedResponse when checkout completes:
struct PazeMaskedCard {
var panLastFour: String
var paymentCardBrand: String
var paymentCardNetwork: String
var paymentCardDescriptor: String
var paymentCardType: String
var digitalCardData: PazeDigitalCardData
var digitalCardId: String?
var paymentAccountReference: String?
var panExpirationMonth: String?
var panExpirationYear: String?
var billingAddress: PazeCheckoutAddress?
}Passed to onComplete:
struct PazeCompleteResult {
var completeDecodedResponse: PazeCompleteDecoded? // payloadId, sessionId, securedPayload
var decryptedPayload: PazeDecryptTokenResponseSuccess? // always nil at onComplete
}Decrypted token data is passed to onPostDecryption when SDK decryption proceeds.
Passed to onPostDecryption:
// decryptedPayload.shopper — fullName, emailAddress, phone fields
// decryptedPayload.billingAddress — addressLine1, city, state, countryCode, postalCode
// decryptedPayload.fundingData — networkToken, expirationMonth, expirationYear, cardNetworkPassed to onPostAuthorisation:
class MerchantSubmitResult {
let merchantTransactionId: String
let systemTransactionId: String
}Typical type received in onSubmitError:
class FailedSubmitResult {
let errorCode: String?
let errorReason: String?
let correlationId: String?
let httpStatusCode: Int?
let details: [String]?
}Passed to onError:
// error.errorCode — e.g. "SDK1213"
// error.errorMessage — human-readable description