Learn about how to configure the click-once component.
The click-once component displays saved cards and allows customers to pay with a single tap. At minimum, you need to configure it with a card submit configuration:
import SwiftUI
import PXPCheckoutSDK
var config = ClickOnceComponentConfig()
var submitConfig = CardSubmitComponentConfig()
submitConfig.onPreAuthorisation = { _ async in
TransactionInitiationData()
}
submitConfig.onPostAuthorisation = { _ in }
config.cardSubmitComponentConfig = submitConfig
let clickOnce = try pxpCheckout.create(.clickOnce, componentConfig: config) as! ClickOnceComponent
clickOnce.buildContent()The click-once component requires ownerType, ownerId, and shopper information to retrieve saved tokens. Configure these in your CheckoutConfig.
Payout support: The click-once component supports card payouts (also called disbursements or withdrawals) where funds are sent from your merchant account to a cardholder's card. This is commonly used for:
- Marketplace seller payments
- Insurance claim settlements
- Refunds and reimbursements
- Competition prizes and rewards
When using intent: TransactionIntentData(card: .payout), configure isRenderLastPayoutCard = true to display cards previously used for successful payouts, providing a familiar payout experience for returning recipients.
You can customise token filtering, sorting, CVC requirements, and button styling:
var config = ClickOnceComponentConfig()
config.limitTokens = 5
config.filterBy = FilterByConfig(
excludeExpiredTokens: true,
schemes: [.visa, .mastercard],
fundingSource: "Credit",
issuerCountryCode: "USA",
ownerType: "Consumer"
)
config.orderBy = OrderByConfig(
expiryDate: OrderByDirectionConfig(direction: "asc", priority: 1),
scheme: OrderByValueConfig(valuesOrder: [.visa, .mastercard, .americanExpress], priority: 2),
lastUsageDate: OrderByLastUsageDateConfig(
orderByField: "lastSuccessfulPurchaseDate",
direction: "desc",
priority: 3
)
)
config.isCvcRequired = true
config.cvcComponentConfig = CardCvcComponentConfig(label: "Security code", isRequired: true)
config.cardBrandImages = CardBrandImages(
visaSrc: Image("CustomVisa"),
mastercardSrc: Image("CustomMC")
)
config.useTransparentCardBrandImage = true
config.hideCardBrandLogo = false
config.submitText = "Pay now"
config.label = "Saved card"
config.transactionInitiatorType = .CIT
config.onOnceCardClick = {
// Runs before payment submission
}
config.onPreRenderTokens = { response in
// Custom token filtering and ordering
response.gatewayTokens.map { CardTokenMapping(id: $0.gatewayTokenId, isCvcRequired: true) }
}
var submitConfig = CardSubmitComponentConfig()
submitConfig.onPreAuthorisation = { _ async in TransactionInitiationData() }
submitConfig.onPostAuthorisation = { _ in }
config.cardSubmitComponentConfig = submitConfig
let clickOnce = try pxpCheckout.create(.clickOnce, componentConfig: config) as! ClickOnceComponent| Property | Description |
|---|---|
cardSubmitComponentConfigCardSubmitComponentConfig? | The card submit configuration for payment processing. Required for handling the payment flow. See Card submit. Defaults to nil. |
limitTokensInt? | The maximum number of tokens to display. Limits how many saved cards are available for selection. Defaults to nil. |
filterByFilterByConfig? | The token filtering options. Allows you to narrow down which saved cards are displayed based on various criteria. Defaults to nil. |
filterBy.excludeExpiredTokensBool? | Whether to exclude expired cards. When true, cards past their expiry date are hidden from the list. Defaults to true. |
filterBy.schemes[TokenScheme]? | The list of accepted card schemes. For example, [.visa, .mastercard] shows only Visa and Mastercard tokens. Defaults to nil. |
filterBy.fundingSourceString? | The funding source filter. For example "Credit" or "Debit" filters to show only cards of that type. Defaults to nil. |
filterBy.issuerCountryCodeString? | The issuer country code filter. Filters tokens by the country where the card was issued. Defaults to nil. |
filterBy.ownerTypeString? | The owner type filter. For example "Consumer" or "Commercial" filters by card ownership type. Defaults to nil. |
orderByOrderByConfig? | The token ordering configuration. Controls how tokens are sorted and displayed. Multiple ordering rules can be applied with priority values. Defaults to nil. |
orderBy.expiryDateOrderByDirectionConfig? | The configuration for sorting by expiry date with direction ("asc" or "desc") and priority. Defaults to nil. |
orderBy.schemeOrderByValueConfig<TokenScheme>? | The configuration for sorting by card scheme with custom order and priority. Defaults to nil. |
orderBy.fundingSourceOrderByValueConfig<String>? | The configuration for sorting by funding source with custom order and priority. Defaults to nil. |
orderBy.ownerTypeOrderByValueConfig<String>? | The configuration for sorting by owner type with custom order and priority. Defaults to nil. |
orderBy.issuerCountryCodeOrderByDirectionConfig? | The configuration for sorting by issuer country with direction and priority. Defaults to nil. |
orderBy.lastUsageDateOrderByLastUsageDateConfig? | The configuration for sorting by last usage date. Allows sorting by purchase or payout activity. Defaults to nil. |
isCvcRequiredBool? | Whether CVC is required for payment. When true, users must enter the security code before submitting. Defaults to nil. |
cvcComponentConfigCardCvcComponentConfig? | The CVC field configuration. Used when isCvcRequired is true. See Card CVC. Defaults to nil. |
hideCardBrandLogoBool? | Whether to hide the brand logo. When true, the card brand image isn't displayed. Defaults to nil. |
useTransparentCardBrandImageBool? | Whether to use transparent brand images. When true, card brand images render without background colours. Defaults to true. |
cardBrandImagesCardBrandImages? | The custom card brand images. Properties: visaSrc, mastercardSrc, amexSrc, cupSrc, dinersSrc, discoverSrc, jcbSrc. Defaults to nil. |
disableCardSelectionBool? | Whether to disable changing the selected card. When true, users can't switch between saved cards. Defaults to nil. |
isRenderLastPurchaseCardBool? | Whether to display the last purchase card. When true, the most recently used card for purchases is displayed. Defaults to nil. |
isRenderLastPayoutCardBool? | Whether to display cards previously used for successful payouts. When true, cards with a lastSuccessfulPayoutDate will be shown even if they haven't been used for purchases. Recommended for payout flows (.payout intent) to show recipients their familiar payout cards. Defaults to nil. |
transactionInitiatorTypeTransactionInitiatorType? | The transaction initiator type. Indicates whether the transaction is customer-initiated (CIT) or merchant-initiated (MIT). Defaults to nil. |
externalTokenIdString? | The specific external token to display. When set, only this token is shown. Defaults to nil. |
expiredTextString? | The text displayed for expired cards. Overrides SDK default. Defaults to nil. |
validThruTextString? | The "Valid thru" label text. Overrides SDK default. Defaults to nil. |
submitTextString? | The submit button text. Overrides SDK default. Defaults to nil. |
labelString? | The section label text. Displayed above the component. Defaults to nil. |
labelAccessibilityLabelString? | The accessibility label for the section label. Defaults to nil. |
submitAccessibilityLabelString? | The accessibility label for the submit button. Defaults to nil. |
selectCardButtonAccessibilityLabelString? | The accessibility label for the card picker button. Defaults to nil. |
cardNumberAccessibilityLabelString? | The accessibility label for the card number display. Defaults to nil. |
cardExpiryDateAccessibilityLabelString? | The accessibility label for the expiry date display. Defaults to nil. |
stylesClickOnceStandaloneStyles? | The container, button, and component styling configuration. Controls the overall appearance of the click-once component. Defaults to nil. |
inputStylesFieldInputStyle? | The shared input styling for CVC field when required. Defaults to nil. |
The click-once component provides event handlers for token management and payment:
config.onPreRenderTokens = { response in
// Custom token filtering and ordering
response.gatewayTokens
.filter { $0.issuerCountryCode == "USA" }
.map { CardTokenMapping(id: $0.gatewayTokenId, isCvcRequired: true) }
}
config.onRetrieveTokensSuccess = { success in
// Token retrieval succeeded
}
config.onRetrieveTokensFailed = { error in
// Handle retrieval error
}
config.onValidationError = { error in
// Handle validation error
}
config.onOnceCardClick = {
// Payment button tapped
}
config.buttonBuilder = { elements in
AnyView(
HStack {
elements.tokenImageView
elements.cardNumberView
elements.cvcComponentView
elements.payButtonView
}
)
}
config.selectTokenItemBuilder = { elements in
AnyView(
HStack {
elements.tokenImageView
elements.cardNumberView
elements.expiryDateView
}
)
}| Callback | Description |
|---|---|
onPreRenderTokens: ((RetrieveCardTokensResponseSuccess) -> [CardTokenMapping])? | Called to pre-process tokens before rendering. Returns an array of CardTokenMapping where each can set id and per-token isCvcRequired. Allows custom filtering and ordering logic. |
onRetrieveTokensSuccess: ((ClickOnceRetrieveTokensSuccess) -> Void)? | Called after successful token retrieval. Receives the response with available tokens. |
onRetrieveTokensFailed: ((ClickOnceRetrieveTokensError) -> Void)? | Called when token retrieval fails. Receives the error details. |
onValidationError: ((BaseSdkException) -> Void)? | Called when validation errors occur. Receives the validation exception details. |
onOnceCardClick: (() -> Void)? | Called when the payment button is tapped, before submission begins. |
buttonBuilder: ((ClickOnceButtonBuilderElements) -> AnyView)? | Custom SwiftUI builder for the payment button layout. Receives pre-built views and returns your custom layout. |
selectTokenItemBuilder: ((ClickOnceSelectTokenBuilderElements) -> AnyView)? | Custom SwiftUI builder for token picker rows. Receives pre-built views and returns your custom layout. |
For more information about event patterns and filtering options, see Events and Card-on-file.
Returns SwiftUI content for the click-once component:
clickOnce.buildContent()A simple click-once payment form:
var config = ClickOnceComponentConfig()
config.submitText = "Pay now"
config.isCvcRequired = true
var submitConfig = CardSubmitComponentConfig()
submitConfig.onPreAuthorisation = { _ async in TransactionInitiationData() }
submitConfig.onPostAuthorisation = { result in
// Handle payment result
}
config.cardSubmitComponentConfig = submitConfig
let clickOnce = try pxpCheckout.create(.clickOnce, componentConfig: config) as! ClickOnceComponentDisplay only specific card types in a custom order:
var config = ClickOnceComponentConfig()
config.filterBy = FilterByConfig(
excludeExpiredTokens: true,
schemes: [.visa, .mastercard],
fundingSource: "Credit"
)
config.orderBy = OrderByConfig(
lastUsageDate: OrderByLastUsageDateConfig(
orderByField: "lastSuccessfulPurchaseDate",
direction: "desc",
priority: 1
)
)
config.limitTokens = 3
var submitConfig = CardSubmitComponentConfig()
submitConfig.onPreAuthorisation = { _ async in TransactionInitiationData() }
submitConfig.onPostAuthorisation = { _ in }
config.cardSubmitComponentConfig = submitConfig
let clickOnce = try pxpCheckout.create(.clickOnce, componentConfig: config) as! ClickOnceComponentEnable 3DS authentication for click-once payments:
var config = ClickOnceComponentConfig()
config.isCvcRequired = true
var submitConfig = CardSubmitComponentConfig()
submitConfig.useUnityAuthenticationStrategy = true
submitConfig.onPreInitiateAuthentication = {
PreInitiateIntegratedAuthenticationData(providerId: "pxpfinancial", timeout: 120)
}
submitConfig.onPreAuthentication = {
InitiateIntegratedAuthenticationData(
merchantCountryNumericCode: "826",
merchantLegalName: "Example Ltd",
challengeWindowSize: .size1,
requestorChallengeIndicator: .challengeRequestedMandate,
timeout: 180
)
}
submitConfig.onPreAuthorisation = { _ async in TransactionInitiationData() }
submitConfig.onPostAuthorisation = { _ in }
config.cardSubmitComponentConfig = submitConfig
let clickOnce = try pxpCheckout.create(.clickOnce, componentConfig: config) as! ClickOnceComponentUse the click-once component to send funds to a cardholder's card (common for marketplace payouts, refunds, or prize disbursements):
let transactionData = TransactionData(
amount: Decimal(string: "150.00")!,
currency: "USD",
entryType: .ecom,
intent: TransactionIntentData(card: .payout), // Critical: Set to payout for disbursements
merchantTransactionId: "payout-\(UUID().uuidString)",
merchantTransactionDate: { Date() }
)
let checkoutConfig = CheckoutConfig(
environment: .test,
session: sessionData,
transactionData: transactionData,
merchantShopperId: "recipient-shopper-id",
ownerType: "MerchantGroup",
ownerId: "your-owner-id",
onGetShopper: { async in TransactionShopper(id: "recipient-shopper-id") }
)
let pxpCheckout = try PxpCheckout.initialize(config: checkoutConfig)
var config = ClickOnceComponentConfig()
config.submitText = "Send funds"
// Enable payout-specific features
config.isRenderLastPayoutCard = true // Show cards used for previous payouts
config.isRenderLastPurchaseCard = false // Optionally hide purchase-only cards
// Sort by most recent payout activity
config.orderBy = OrderByConfig(
lastUsageDate: OrderByLastUsageDateConfig(
orderByField: "lastSuccessfulPayoutDate",
direction: "desc",
priority: 1
)
)
config.isCvcRequired = true
var submitConfig = CardSubmitComponentConfig()
submitConfig.onPreAuthorisation = { _ async in
TransactionInitiationData(
riskScreeningData: RiskScreeningData(
performRiskScreening: true,
excludeDeviceData: false,
deviceSessionId: generateDeviceSessionId(),
userIp: "192.168.1.100",
account: RiskScreeningAccount(
id: "recipient_12345",
creationDateTime: "2024-01-15T10:30:00.000Z"
),
fulfillments: [
RiskScreeningFulfillment(
type: .shipped,
recipientPerson: RiskScreeningRecipientPerson(
phoneNumber: "+1234567890"
)
)
]
)
)
}
submitConfig.onPostAuthorisation = { result in
if result is MerchantSubmitResult {
print("Payout completed")
// Navigate to payout confirmation screen
}
}
config.cardSubmitComponentConfig = submitConfig
let clickOnce = try pxpCheckout.create(.clickOnce, componentConfig: config) as! ClickOnceComponent
private func generateDeviceSessionId() -> String {
return UUID().uuidString.replacingOccurrences(of: "-", with: "")
}When using .payout intent, funds move from your merchant account to the cardholder's card. Ensure you:
- Have sufficient balance in your gateway account.
- Use appropriate messaging ("withdraw", "receive", "send to your card").
- Verify recipient card eligibility for disbursements (not all cards support payouts).
For 3DS details, see 3DS transactions. For validation behaviour, see Data validation.