# Configuration

Learn how to configure the Aeropay button component for iOS.

## Basic usage

### Minimal configuration

At minimum, the Aeropay button requires an Aeropay-enabled session and valid transaction data on SDK initialisation. You can then create the component with its default presentation:

```swift
let config = AeropayButtonComponentConfig()
config.onPreAuthorisation = { true }
config.onPostAuthorisation = { result in
    verifyPaymentOnBackend(result)
}
config.onError = { error in
    // Handle flow errors using error.errorCode and error.errorMessage
}

let aeropayButton = try pxpCheckout.create(.aeropayButton, componentConfig: config)
```

Always verify the transaction on your backend before fulfilling an order or confirming a payout. Client callbacks can be manipulated by malicious users.

### Related SDK configuration

Configure the session and transaction before creating the Aeropay button:

```swift
let checkoutConfig = CheckoutConfig(
    environment: .test,
    session: sessionData,
    transactionData: TransactionData(
        amount: Decimal(25.00),
        currency: "USD",
        entryType: .ecom,
        intent: TransactionIntentData(aeropay: .authorisation),
        merchantTransactionId: UUID().uuidString,
        merchantTransactionDate: { Date() }
    ),
    merchantShopperId: "shopper-123",
    ownerId: "MERCHANT_GROUP_1",
    onGetShopper: { TransactionShopper(
            id: "shopper-123",
            firstName: "John",
            lastName: "Doe",
            email: "john.doe@example.com",
            phoneNumber: "+14155550123"
        )
    }
)
```

The following SDK options affect the Aeropay component:

| Property | Description |
|  --- | --- |
| `session`SessionData | Session data from your backend. It must include `allowedFundingTypes.payByBanks.aeropay` with non-empty `externalMerchantId` and `configurationId`. |
| `ownerId`String | Your merchant group identifier. |
| `transactionData.currency`String | Transaction currency. Aeropay supports `USD`. |
| `transactionData.entryType`EntryType | Transaction entry type. Set this to `.ecom`. |
| `transactionData.intent.aeropay`AeropayIntentType | Aeropay transaction intent. Supported values are `.authorisation`, `.purchase`, `.estimatedAuthorisation`, and `.payout`. |
| `onGetShopper`() async -> TransactionShopper? | Supplies shopper details for the new-shopper flow. The component can prefill `firstName`, `lastName`, `email`, and `phoneNumber`. |


## Component properties

Use these properties when configuring `AeropayButtonComponentConfig`:

| Property | Description |
|  --- | --- |
| `userId`String? | A verified Aeropay user ID. The SDK validates that the user is active, then skips consumer data collection and OTP verification. |
| `skipConsumerDataCollection`Bool | When `true`, skips the consumer data screen if `onGetShopper` supplies all four required fields and `editableFields` is omitted, `nil`, or empty. Defaults to `false`. |
| `label`String? | Custom text for the payment button when the intent isn't `.payout`. If omitted, the SDK uses the localised default label (en-US: `Pay by bank`). For `.payout`, the SDK always uses the localised payout label (en-US: `Withdraw by Bank`) and ignores `label`. |
| `disabled`Bool | Whether the payment button starts disabled. Defaults to `false`. After creation, call `setDisabled(_:)` to change the button state. |
| `styles`ButtonStateStyles? | Styles for the payment button. See [Button styles](#button-styles). |
| `popupConfig`AeropayPopupConfig? | Styles for the popup container, shared action buttons, and intro cards. |
| `consumerDataCollectionConfig`ConsumerDataCollectionConfig? | Field behaviour and styling for the consumer data screen. |
| `otpVerificationConfig`OtpVerificationConfig? | Styling for the OTP verification screen. |
| `bankSelectionConfig`BankSelectionConfig? | Behaviour and styling for bank selection and the Aerosync experience. |


## Shopper flow configuration

### New shoppers

Don't set `userId` when the shopper doesn't have a verified Aeropay account. The SDK uses `onGetShopper` to prefill the consumer data screen:

```swift
let config = AeropayButtonComponentConfig()
config.onUserVerificationSuccess = { user in
    saveAeropayUserId(user.id)
}
```

Store `user.id` securely after verification so you can identify the shopper on future visits.

### Skip consumer data collection

Set `skipConsumerDataCollection` to `true` to start the new-shopper flow at OTP verification:

```swift
let checkoutConfig = CheckoutConfig(
    // ...session and transaction configuration
    onGetShopper: { TransactionShopper(
            firstName: "John",
            lastName: "Doe",
            email: "john.doe@example.com",
            phoneNumber: "+14155550123"
        )
    }
)

let config = AeropayButtonComponentConfig()
config.skipConsumerDataCollection = true
```

The component skips the consumer data screen only when all of these conditions are met:

* `onGetShopper` returns valid, non-empty `firstName`, `lastName`, `email`, and `phoneNumber` values.
* `skipConsumerDataCollection` is `true`.
* `consumerDataCollectionConfig.editableFields` is omitted, `nil`, or empty.


`phoneNumber` must be a valid US E.164 value with a `+1` prefix (e.g., `+14155550123`). Empty values don't satisfy the skip path. Invalid non-empty values (e.g., a phone without `+1` and ten digits) call `onError` with `SDK1300` before the popup opens, rather than falling back to the consumer data screen.

If a value is missing or empty, or `editableFields` contains a field, the component shows the consumer data screen.

### Returning shoppers

Pass a verified Aeropay user ID to skip data collection and OTP verification:

```swift
let config = AeropayButtonComponentConfig()
config.userId = "c7582e95-d9a1-42c3-b0e3-ee6bc98764ec"
```

If the user is active, the SDK validates the user, then opens the popup at the Aerosync bank-selection screen. If the user isn't active, `onError` receives `SDK1307`. If retrieving the user fails, `onError` receives `SDK1308`. Clear the stored `userId` and restart the new-shopper flow.

## Popup configuration

Use `popupConfig` to customise the popup container, shared action buttons, and intro cards:

```swift
config.popupConfig = AeropayPopupConfig(
    styles: AeropayViewStyleConfig(
        fontFamily: "Source Code Pro",
        foregroundColor: .black,
        backgroundColor: .white,
        cornerRadius: 20,
        padding: EdgeInsets(top: 16, leading: 16, bottom: 16, trailing: 16)
    ),
    actionButtonStyles: ButtonStateStyles(
        base: FieldStyle(
            backgroundColor: Color(red: 47 / 255, green: 59 / 255, blue: 1),
            color: .white
        )
    ),
    introStyles: ScreenIntroStyleConfig(
        backgroundColor: Color(red: 219 / 255, green: 237 / 255, blue: 250 / 255),
        cornerRadius: 12
    )
)
```

Configure the popup with these properties:

| Property | Description |
|  --- | --- |
| `styles`AeropayViewStyleConfig? | Popup container styles for font, colours, border, corner radius, and padding. |
| `actionButtonStyles`ButtonStateStyles? | Shared styles for action buttons on popup screens. Screen-level button styles override these values. |
| `introStyles`ScreenIntroStyleConfig? | Styles for the intro card on the consumer data and OTP screens. |


## Consumer data configuration

Use `consumerDataCollectionConfig` to control which prefilled fields remain editable and to customise the form:

```swift
config.consumerDataCollectionConfig = ConsumerDataCollectionConfig(
    editableFields: [.email, .phoneNumber],
    fieldConfig: ConsumerDataFieldConfig(
        labelStyles: FieldLabelStateStyles(
            base: FieldLabelStyle(color: Color(white: 0.2))
        ),
        inputStyles: FieldInputStateStyles(
            base: FieldInputStyle(borderColor: Color(white: 0.8)),
            invalid: FieldInputStyle(borderColor: .red)
        ),
        invalidTextStyle: FieldMessageStyle(color: .red),
        phoneNumberGuideTextStyle: FieldMessageStyle(fontSize: 12)
    ),
    buttonStyles: ButtonStateStyles(
        base: FieldStyle(backgroundColor: Color(red: 47 / 255, green: 59 / 255, blue: 1))
    )
)
```

The consumer data screen supports these properties:

| Property | Description |
|  --- | --- |
| `editableFields`[ConsumerDataField]? | Prefilled fields that the shopper can edit. Possible values are `.firstName`, `.lastName`, `.email`, and `.phoneNumber`. When `nil` or empty, prefilled fields are read-only. |
| `fieldConfig.labelStyles`FieldLabelStateStyles? | Label styles for the base, valid, and invalid states. |
| `fieldConfig.inputStyles`FieldInputStateStyles? | Input styles for the base, valid, and invalid states. |
| `fieldConfig.invalidTextStyle`FieldMessageStyle? | Styles for validation messages. |
| `fieldConfig.phoneNumberPrefixStyle`FieldPrefixStyle? | Styles for the phone number `+1` prefix. |
| `fieldConfig.phoneNumberGuideTextStyle`FieldMessageStyle? | Styles for the phone number guidance text. |
| `buttonStyles`ButtonStateStyles? | Styles for the screen's action button. |


Fields returned by `onGetShopper` are disabled by default. Add a field to `editableFields` if the shopper needs to change its value.

## OTP verification configuration

Use `otpVerificationConfig` to customise the OTP inputs, validation message, and action button:

```swift
config.otpVerificationConfig = OtpVerificationConfig(
    inputStyles: FieldInputStateStyles(
        base: FieldInputStyle(borderColor: .gray, cornerRadius: 8),
        active: FieldInputStyle(borderColor: .blue, borderWidth: 2),
        invalid: FieldInputStyle(borderColor: .red)
    ),
    invalidTextStyles: FieldMessageStyle(color: .red),
    buttonStyles: ButtonStateStyles(
        base: FieldStyle(backgroundColor: Color(red: 47 / 255, green: 59 / 255, blue: 1))
    )
)
```

Configure the OTP verification screen with these properties:

| Property | Description |
|  --- | --- |
| `inputStyles`FieldInputStateStyles? | Styles for each OTP input in the base, active, and invalid states. |
| `invalidTextStyles`FieldMessageStyle? | Styles for the validation message below the OTP inputs. |
| `buttonStyles`ButtonStateStyles? | Styles for the verification button. |


## Bank selection configuration

Use `bankSelectionConfig` to customise bank selection and the embedded Aerosync experience:

```swift
config.bankSelectionConfig = BankSelectionConfig(
    payButtonStyles: ButtonStateStyles(
        base: FieldStyle(backgroundColor: Color(red: 47 / 255, green: 59 / 255, blue: 1))
    ),
    linkBankButtonStyles: ButtonStateStyles(
        base: FieldStyle(
            backgroundColor: .white,
            color: Color(red: 47 / 255, green: 59 / 255, blue: 1)
        )
    ),
    bankSelectedIndicatorColor: Color(red: 47 / 255, green: 59 / 255, blue: 1),
    bankItemStyles: BankItemStateStyles(
        base: BankItemStyle(
            bankNameStyle: BankItemTextStyle(fontSize: 16)
        ),
        selected: BankItemStyle(
            containerStyle: BankItemContainerStyle(
                backgroundColor: Color(red: 219 / 255, green: 237 / 255, blue: 250 / 255)
            )
        )
    ),
    excludedBankAccountIds: ["12345"],
    allowLinkBankOnPayout: false,
    aerosyncTheme: .light
)
```

Configure the bank selection screen with these properties:

| Property | Description |
|  --- | --- |
| `payButtonStyles`ButtonStateStyles? | Styles for the pay or withdraw button. |
| `linkBankButtonStyles`ButtonStateStyles? | Styles for the link-bank button. |
| `bankSelectedIndicatorColor`Color? | Accent colour for the selected-bank indicator. When `bankItemStyles` isn't set, the SDK can derive bank item styles from this colour. |
| `bankItemStyles`BankItemStateStyles? | Styles for funding bank list items in the base and selected states. |
| `excludedBankAccountIds`[AeropayBankAccountId]? | Optional list of bank account IDs to hide from the bank selection screen. Values can be string or integer literals (e.g., `"12345"` or `12345`). |
| `allowLinkBankOnPayout`Bool | Whether to show the link-bank button for `.payout` transactions. Defaults to `false`. |
| `aerosyncTheme`AerosyncTheme? | Theme for the embedded Aerosync widget. Use `.light` or `.dark`. When omitted, the SDK resolves light theme. |


## Button styles

The top-level `styles` property and each screen's button style property use `ButtonStateStyles`:

```swift
let buttonStyles = ButtonStateStyles(
    base: FieldStyle(
        backgroundColor: Color(red: 47 / 255, green: 59 / 255, blue: 1),
        color: .white,
        cornerRadius: 8,
        padding: EdgeInsets(top: 14, leading: 16, bottom: 14, trailing: 16)
    ),
    disabled: FieldStyle(
        backgroundColor: Color(red: 47 / 255, green: 59 / 255, blue: 1).opacity(0.5)
    )
)
```

Configure button states with these properties:

| Property | Description |
|  --- | --- |
| `base`FieldStyle? | Styles for the default state. |
| `disabled`FieldStyle? | Styles applied when the button is disabled. |
| `loading`FieldStyle? | Styles applied while the button is in a loading state. |


## Event handling

Configure callbacks on the component to respond to shopper actions, validation, verification, transaction submission, and errors:

```swift
let config = AeropayButtonComponentConfig()
config.onClick = {
    clearPaymentErrors()
}
config.onCustomValidation = {
    await validateCheckoutReady()
}
config.onUserVerificationSuccess = { user in
    saveAeropayUserId(user.id)
}
config.onCancel = {
    resetCheckoutState()
}
config.onPreAuthorisation = { true }
config.onPostAuthorisation = { result in
    verifyPaymentOnBackend(result)
}
config.onSubmitError = { error in
    // Handle FailedSubmitResult from transaction submission
}
config.onError = { error in
    // Handle BaseSdkException from the Aeropay flow
}
```

The component supports these callbacks:

| Callback | Description |
|  --- | --- |
| `onClick`() -> Void | Called when the shopper taps the Aeropay button, before custom validation and popup opening. |
| `onCustomValidation`() async -> Bool | Called after `onClick`. Return `true` to continue or `false` to stop before the Aeropay flow starts. |
| `onUserVerificationSuccess`(AeropayUser) -> Void | Called after OTP verification succeeds. Store `user.id` for returning-shopper flows. |
| `onCancel`() -> Void | Called when the shopper dismisses the popup. Programmatic dismissal after a successful payment doesn't invoke it. |
| `onPreAuthorisation`() async -> Bool | Called before transaction submission. Return `true` to proceed or `false` to stop. |
| `onPostAuthorisation`(MerchantSubmitResult) -> Void | Called after the transaction is submitted successfully. |
| `onSubmitError`(BaseSubmitResult) -> Void | Called when transaction submission fails. At runtime, failed responses typically use `FailedSubmitResult`. |
| `onError`(BaseSdkException) -> Void | Called when an SDK or provider error occurs during the Aeropay flow outside successful or failed transaction submission. |


For callback payloads and handling guidance, see [Events](/guides/checkout/components/ios/aeropay/events).

## Methods

### `buildContent()`

Render the Aeropay button in your SwiftUI view:

```swift
aeropayButton.buildContent()
    .frame(maxWidth: .infinity)
```

Create the component through `pxpCheckout.create(.aeropayButton, componentConfig:)`. Direct instantiation isn't supported.

### `setDisabled(_:)`

Update the button's disabled state after creation:

```swift
if let aeropayButton = component as? AeropayButtonComponent {
    aeropayButton.setDisabled(true)
}
```

`create` returns `BaseComponent`, so cast to `AeropayButtonComponent` before calling `setDisabled`, `hide`, or `show`.

### `hide()` / `show()`

Hide or show the button after creation:

```swift
if let aeropayButton = component as? AeropayButtonComponent {
    aeropayButton.hide()
    aeropayButton.show()
}
```