# Launch The Paysheet (/limited-release/paypal-mobile-checkout/launch-sdk)



Follow these steps to add payment buttons to your app or programmatically start the SDK

## iOS [#ios]

## Payment Buttons [#payment-buttons]

## PaymentButtonContainer [#paymentbuttoncontainer]

The `PaymentButtonContainer` is responsible for displaying the payment buttons. This container can display three different buttons: the PayPal button, the PayPal Credit button, and the Pay Later button. By default the `PaymentButtonContainer` displays the PayPal button.

> **Note:** **Note:** `PaymentButtonContainer` does not support PayPal Credit and Pay Later. Those buttons will return as not eligible. No matter how you configure the `PaymentButtonContainer`, you will only see the PayPal button.

The `PaymentButtonContainer` provides the callbacks needed to integrate with the native checkout experience: `CreateOrder`, `OnApprove`, `OnError`, `OnCancel`, and `OnShippingChange`.

### Customize the buttons [#customize-the-buttons]

Each button type has a corresponding configuration object. To customize the buttons' appearance, you can instantiate `PayPalButtonUIConfiguration`, `PayPalCreditButtonUIConfiguration`, and `PayLaterButtonUIConfiguration` objects with custom parameters. Finally, you instantiate the `PaymentButtonContainer` passing in these configuration instances. If you don't pass any configuration objects to the `PaymentButtonContainer` initializer, it will use default configuration values.

#### Swift

```text lineNumbers
// Create custom configuration objects
let attributes = PaymentButtonAttributes(
    edges: .softEdges,
    size: .expanded,
    isEnabled: true
)
let payPalUIConfig = PayPalButtonUIConfiguration(
    color: .blue,
    label: nil,
    attributes: attributes
)
let payPalCreditUIConfig = PayPalCreditButtonUIConfiguration(
    color: .white,
    attributes: attributes
)
let payLaterUIConfig = PayLaterButtonUIConfiguration(
    color: .black,
    attributes: attributes
)
// Instantiate the container passing the configuration objects
let container = PaymentButtonContainer(
    payPalButtonUIConfiguration: payPalUIConfig,
    payPalCreditButtonUIConfiguration: payPalCreditUIConfig,
    payLaterButtonUIConfiguration: payLaterUIConfig,
)
// Display the container
view.addSubview(container)
NSLayoutConstraint.activate(
    [
        container.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        container.centerXAnchor.constraint(equalTo: view.centerXAnchor)
    ]
)
```

#### Obj-C

```text lineNumbers
// Create custom configuration objects
PPCPaymentButtonAttributes *attributes = [[PPCPaymentButtonAttributes alloc]
    initWithEdges: PPCPaymentButtonEdgesSoftEdges
    size: PPCPaymentButtonSizeExpanded
    isEnabled: true];
PPCPayPalButtonUIConfiguration*payPalUIConfig = [[PPCPayPalButtonUIConfiguration alloc]
    initWithColor: PPCPayPalButtonColorGold
    label: PPCPayPalButtonLabelBuyNow
    attributes: attributes];
PPCPayPalCreditButtonUIConfiguration *payPalCreditUIConfig = [[PPCPayPalCreditButtonUIConfiguration alloc]
    initWithColor: PPCPayPalCreditButtonColorDarkBlue
    attributes: attributes];
PPCPayLaterButtonUIConfiguration*payPalUILaterConfig = [[PPCPayLaterButtonUIConfiguration alloc]
    initWithColor: PPCPayPalPayLaterButtonColorBlue
    attributes: attributes];
// Instantiate the container passing the configuration objects
PPCPaymentButtonContainer *container = [[PPCPaymentButtonContainer alloc]
    initWithPayPalButtonUIConfiguration: payPalUIConfig
    payPalCreditButtonUIConfiguration: payPalCreditUIConfig
    payLaterButtonUIConfiguration: payPalUILaterConfig];
// Display the container
[[self view] addSubview: container];
[NSLayoutConstraint activateConstraints: @[
    [[container centerYAnchor] constraintEqualToAnchor: self.view.centerYAnchor],
    [[container centerXAnchor] constraintEqualToAnchor: self.view.centerXAnchor],
]];
```

### Attributes [#attributes]

The `PaymentButtonAttributes` class contains the three properties that are common to all button types:

| Property    | Description                                                                                                                                 |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `edges`     | Overrides the shape of the button. The default value is `softEdges`, but you can also set it to `hardEdges` or `rounded`.                   |
| `size`      | Adjusts the size of the button. The default value is `collapsed`, but you can also set it to: `expanded`, `full`, or `mini`.                |
| `isEnabled` | Determines whether or not to show this button. If this button type is ineligible, this flag will be ignored and the button won't be showed. |

### PayPal button [#paypal-button]

You can customize the appearance of the PayPal button via the `PayPalButtonUIConfiguration`, which contains the following attributes:

| Property     | Description                                                                                                                                                                              |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `color`      | Changes the background color of the button and adjusts the wordmark color to be visible. The default value is `gold`, but you can also set it to: `white`, `black`, `silver`, or `blue`. |
| `label`      | Adds a label next to the button logo. The default value is no label, but you can also set it to: `checkout`, `buyNow`, or `payWith`.                                                     |
| `attributes` | The button attributes defined by `PaymentButtonAttributes`.                                                                                                                              |

### PayPal Credit button [#paypal-credit-button]

You can customize the appearance of the PayPal Credit button via the `PayPalCreditButtonUIConfiguration`, which contains the following attributes:

| Property     | Description                                                                                                                                                               |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `color`      | Changes the background color of the button and adjusts the wordmark color to be visible. The default value is `darkBlue`, but you can also set it to: `white` or `black`. |
| `attributes` | The button attributes defined by `PaymentButtonAttributes`.                                                                                                               |

### Pay Later button [#pay-later-button]

You can customize the appearance of the Pay Later button via the `PayLaterButtonUIConfiguration`, which contains the following attributes:

| Property     | Description                                                                                                                                                                              |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `color`      | Changes the background color of the button and adjusts the wordmark color to be visible. The default value is `gold`, but you can also set it to: `white`, `black`, `silver`, or `blue`. |
| `attributes` | The button attributes defined by `PaymentButtonAttributes`.                                                                                                                              |

### Callbacks [#callbacks]

The `PaymentButtonContainer` provides the callbacks needed to integrate with the native checkout experience: `createOrder`, `onApproval`, `onError`, `onCancel`, and `onShippingChange`.

#### Swift

```text lineNumbers
let container = PaymentButtonContainer(delegate: self)
container.createOrder = { action in
    print("Create order here from (action)")
}
container.onCancel = {
    print("Cancelled")
}
container.onError = { error in
    print("Failed with error: (error)")
}
container.onApproval = { approval in
    print("Got approval: (approval)")
}
container.onShippingChange = { change, action in
    print("Shipping changed: (change) (action)")
}
```

#### Obj-C

```text lineNumbers
PPCPaymentButtonContainer*container = [[PPCPaymentButtonContainer alloc] initWithDelegate: self];
container.createOrder = ^(PPCCreateOrderAction*_Nonnull) {
            NSLog(@"create order action");
        };
container.onApproval = ^(PPCApproval*_Nonnull) {
            NSLog(@"on approval");
        };
        container.onError = ^(PPCErrorInfo *_Nonnull) {
            NSLog(@"on error");
        };
        container.onCancel = ^{
            NSLog(@"on cancel");
        };
container.onShippingChange = ^(PPCShippingChange*_Nonnull, PPCShippingChangeAction*_Nonnull) {
            NSLog(@"on shipping change");
        };
```

### Delegate functions [#delegate-functions]

You can also observe the view state of the `PaymentButtonContainer` using the `PaymentButtonContainerDelegate`'s `onLoading()` and `onFinish()` callbacks.

* The `onLoading` and `onFinish` callbacks are invoked during the network call to check for buyer eligibility.
* The `onLoading` callback is invoked at the start of the eligibility network call and the `PaymentButtonContainer` view begins loading.
* The `onFinish` callback is invoked when the eligibility network call has completed.

These callbacks can be implemented like so

#### Swift

```text lineNumbers
// MARK: - PaymentButtonContainerDelegate
    func onLoading() {
        print("PaymentButtonContainer is loading...")
    }
    func onFinish(fundingEligibilityState: PaymentFundingEligibilityState?) {
        print("PaymentButtonContainer finished loading")
    }
```

#### Obj-C

```text lineNumbers
#pragma mark - PaymentButtonContainerDelegate
    - (void)onLoading { NSLog(@"PaymentButtonContainer is loading..."); }
    - (void)onFinishWithFundingEligibilityState:(PPCPaymentFundingEligibilityState *)fundingEligibilityState { NSLog(@"PaymentButtonContainer finished loading"); }
```

The `fundingEligibilityState` contains a map of each `PaymentButtonFundingSource`available. This includes the default PayPal payment funding type as well as PayPal Credit and Pay Later. A `PaymentButtonFundingSource` may not be eligible for the buyer to use. The payment button for the funding type will not be visible if the funding type is not eligible. If there's a failure in the request, the `error` object within `fundingEligibilityState` will contain the error.

**PaymentButtonContainer does not support PayPal Credit and Pay Later. Those buttons will return as not eligible.**

## Payment Buttons (Deprecated) [#payment-buttons-deprecated]

> **Note:** **Note:** `PayPalButton`, `PayPalCreditButton`, and `PayPalPayLaterButton`are deprecated in favor of `PaymentButtonContainer`. This section is provided as a reference to those using previous versions.

### Migrating to PaymentButtonContainer [#migrating-to-paymentbuttoncontainer]

To migrate to `PaymentButtonContainer`, follow these steps:

* Replace `PayPalButton`, `PayPalCreditButton`, and `PayPalPayLaterButton`references with `PaymentButtonContainer`.
* Instead of setting up each payment button individually, you now only need to call `PaymentButtonContainer` initializer passing your custom configuration objects.
* Instead of observing the `eligibilityStatus` for a payment button with `onEligibilityStatusChanged`, use the `onLoading()` and `onFinish()` callbacks provided by the `PaymentButtonContainerDelegate` for the `PaymentButtonContainer` as detailed in the `PaymentButtonContainerDelegate`section above.

### PayPal button [#paypal-button-1]

You can customize the appearance of the `PayPalButton` in the following ways:

| Property | Description                                                                                                                                                                              |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `color`  | Changes the background color of the button and adjusts the wordmark color to be visible. The default value is `gold`, but you can also set it to: `black`, `blue`, `silver`, or `white`. |
| `edges`  | Overrides the shape of the button. The default value is `softEdges`, but you can also set it to `hardEdges` or `rounded`.                                                                |
| `label`  | Adds a label next to the button logo. The default value is no label, but you can also set it to: `checkout`, `buyNow`, or `payWith`.                                                     |
| `size`   | Adjusts the size of the button. The default value is `collapsed`, but you can also set it to: `expanded`, `full`, or `mini`.                                                             |

### Pay Later button [#pay-later-button-1]

You can customize the appearance of the `PayPalPayLaterButton` in the following ways:

| Property | Description                                                                                                                                                                              |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `color`  | Changes the background color of the button and adjusts the wordmark color to be visible. The default value is `gold`, but you can also set it to: `black`, `blue`, `silver`, or `white`. |
| `edges`  | Overrides the shape of the button. The default value is `softEdges`, but you can also set it to `hardEdges` or `rounded`.                                                                |
| `size`   | Adjusts the size of the button. The default value is `collapsed`, but you can also set it to: `expanded`, `full`, or `mini`.                                                             |

### PayPal Credit button [#paypal-credit-button-1]

| Property | Description                                                                                                                                                             |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `color`  | Changes the background color of the button and adjust the wordmark color to be visible. The default value is `darkBlue`, but you can also set it to `black` or `white`. |
| `edges`  | Overrides the shape of the button. The default value is `softEdges`, but you can also set it to `hardEdges` or `rounded`.                                               |
| `size`   | Adjusts the size of the button. The default value is `collapsed`, but you can also set it to: `expanded`, `full`, or `mini`.                                            |

### Payment button eligibility [#payment-button-eligibility]

To ensure buyers have an optimal experience, every `PaymentButton` adheres to strict eligibility requirements. Generally, the `PayPalButton` is always `Eligible` so it's safe to fallback for other buttons.

Eligibility updates are communicated through a `delegate` property of the `PaymentButton`. To receive these events, conform to `PaymentButtonDelegate`:

```javascript lineNumbers
class CheckoutView: UIView, PaymentButtonDelegate {

    var payPalButton = PayPalButton()

    func configurePayPalButton() {
        payPalButton.delegate = self
    }

    func onButtonStart(_ button: PaymentButton) {
        // Invoked when the button is selected, before the checkout process begins.
    }

    func onButtonFinish(_ button: PaymentButton) {
        // Invoked when the checkout process has finished
    }

    func button(_ button: PaymentButton, changedEligibilityStatus status: PaymentButtonEligibilityStatus) {
        // Invoked when the eligibility status of the button has changed
    }
}
```

Both properties emit one value at a minimum, as the current value is emitted when either property is set. This is useful because the SDK retrieves funding eligibility requirements as soon as `PayPalCheckout.setConfig` is invoked. Usually, the funding eligibility retrieves by the time the `PaymentButton` renders. If funding eligibility isn't retrieved, the buttons are disabled and display a loading state.

You can also retrieve the current status through the `eligibilityStatus` property. The following are possible values:

| Status       | Description                                                                                                                          |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| `eligible`   | The button is visible and enabled, so buyers can interact with it.                                                                   |
| `error`      | The button is disabled and the visibility is hidden. This status only returns if there's an error retrieving the eligibility status. |
| `ineligible` | The button is disabled and the visibility is hidden.                                                                                 |
| `loading`    | The button is disabled and the visibility is hidden.                                                                                 |

## Custom UI [#custom-ui]

If you use a custom UI to launch the PayPal Checkout experience, you need to programmatically start the PayPal Mobile Checkout SDK.

## Launch the SDK [#launch-the-sdk]

Instead of invoking the payment sheet by adding a button with the event closures set on the `Checkout` type, provide the closures directly to the SDK through `Checkout.start`.

This sample code creates an order of a single item for $10.00 USD.

#### Swift

```text lineNumbers
func triggerPayPalCheckout() {
    Checkout.start(
        createOrder: { createOrderAction in
            let amount = PurchaseUnit.Amount(currencyCode: .usd, value: "10.00")
            let purchaseUnit = PurchaseUnit(amount: amount)
            let order = OrderRequest(intent: .capture, purchaseUnits: [purchaseUnit])
            createOrderAction.create(order: order)
        }, onApprove: { approval in
            // Optionally use this closure to respond to the order approval
        }, onCancel: {
            // Optionally use this closure to respond to the user canceling the paysheet
        }, onError: { error in
            // Optionally use this closure to respond to the user experiencing an error in
            // the payment experience
        }
    )
}
```

#### Obj-C

```text lineNumbers
PPCheckout *start = [
createOrder:^(PPCCreateOrderAction*action) {
          PPCPurchaseUnitAmount *purchaseUnitAmount = [
            [PPCPurchaseUnitAmount alloc] initWithCurrencyCode:PPCCurrencyCodeUsd
              value:@"5.00"
              breakdown:nil;
            ]
          ];
            PPCPurchaseUnit*purchaseUnit = [
            [PPCPurchaseUnit alloc] initWithAmount:purchaseUnitAmount
            referenceId:nil
            payee:nil
            paymentInstruction:nil
            purchaseUnitDescription:nil
            customId:nil
            invoiceId:nil
            softDescriptor:nil
            items:nil
            shipping:nil
          ];
          PPCOrderRequest *order = [
            [PPCOrderRequest alloc] initWithIntent:PPCOrderIntentAuthorize
            purchaseUnits:@[purchaseUnit]
            payer:nil
            applicationContext:nil
          ];
          [action createWithOrder:order completion:nil];
        }
onApprove:^(PPCApproval*approval) {
        approval.actions capture:^(PPCApprovalResponse *response, NSError*error) {
            NSLog(@"Order successfully captured:" %@, response.data);
        }
    }
onCancel:^(PPCCancel*cancel) {
        // Optionally use this closure to respond to the user canceling the paysheet
    }
onError:^(PPCError*error) {
        // Optionally use this closure to respond to the user experiencing an error in
        // the payment experience
    }
];
```

## Android [#android]

## Payment Buttons [#payment-buttons-1]

## PaymentButtonContainer [#paymentbuttoncontainer-1]

The `PaymentButtonContainer` is responsible for displaying the payment buttons. This container can display three different buttons: the PayPal button, the PayPal Credit button, and the Pay Later button. By default the `PaymentButtonContainer` displays the PayPal button.

> **Note:** **Note:** `PaymentButtonContainer` does not support PayPal Credit and Pay Later. Those buttons will return as not eligible. No matter how you configure the `PaymentButtonContainer`, you will only see the PayPal button.

The `PaymentButtonContainer` provides the callbacks needed to integrate with the native checkout experience: `CreateOrder`, `OnApprove`, `OnError`, `OnCancel`, and `OnShippingChange`.

### Customize the buttons [#customize-the-buttons-1]

For most integrations, the default `PaymentButtonContainer` is sufficient. However, if you want greater control over your buttons customization, you can customize the buttons. You can change the payment button's style. This includes the button's `label`, `color`, `shape`, and `size`. You can also enable or disable the payment button. The payment button will only be shown if the button is enabled and that funding option is eligible for the buyer.

#### Kotlin

```text lineNumbers
paymentButtonContainer.setPayPalButtonUi(
    paypalButtonUi = PayPalButtonUi(
        PayPalButtonColor.BLUE,
        PayPalButtonLabel.CHECKOUT,
        PaymentButtonAttributes(
            PaymentButtonShape.ROUNDED,
            PaymentButtonSize.LARGE,
            isEnabled =  true
        )
    )
)
paymentButtonContainer.setup(
    createOrder = CreateOrder { createOrderActions ->
        createOrderActions.create(OrderRequest())
    },
    onApprove = OnApprove { approval ->
        Log.d(TAG, "orderId: ${approval.data.orderId}")
    },
    onError = OnError { errorInfo ->
        Log.e(TAG, errorInfo.reason, errorInfo.error)
    },
    onCancel = OnCancel {
        Log.i(TAG, "cancelled")
    },
    onShippingChange = OnShippingChange { shippingChangeData, shippingChangeActions ->
        Log.i(TAG, "Shipping type change: ${shippingChangeData.shippingChangeType}")
    }
)
```

#### Java

```text lineNumbers
paymentButtonContainer.setPayPalButtonUi(
        new PayPalButtonUi(
                PayPalButtonColor.BLUE,
                PayPalButtonLabel.CHECKOUT,
                new PaymentButtonAttributes(
                        PaymentButtonShape.ROUNDED,
                        PaymentButtonSize.LARGE,
                        true
                )
        )
);
paymentButtonContainer.setup(
        createOrderActions -> createOrderActions.create(new OrderRequest()),
        approval ->  {
            Log.i(TAG, "orderId: " + approval.getData().getOrderId());
        },
        (shippingChangeData, shippingChangeActions) -> {
            Log.i(TAG, "Shipping type change: " + shippingChangeData.getShippingChangeType());
        },
        () -> Log.i(TAG, "cancelled"),
        errorInfo -> Log.e(TAG, errorInfo.getReason(), errorInfo.getError())
);
```

### Payment Button Container View State [#payment-button-container-view-state]

You can also observe the view state of the `PaymentButtonContainer` using the `PaymentButtonContainerViewState`'s `onLoading()` and `onFinish()` callbacks.

* The `onLoading` and `onFinish` callbacks are invoked during the network call to check for buyer eligibility.
* The `onLoading` callback is invoked at the start of the eligibility network call and the `PaymentButtonContainer` view begins loading.
* The `onFinish` callback is invoked when the eligibility network call has completed.

These callbacks can be implemented like so:

#### Kotlin

```text lineNumbers
paymentButtonContainer.viewState = PaymentButtonContainerViewState.invoke(
    onLoading = {
        Log.d(TAG, "Loading")
    },
    onFinish = { fundingEligibilityState, exception ->
        fundingEligibilityState?.let { state ->
            state.paymentsButtonMap?.let { map ->
                map.entries.forEach {
                    val paymentFundingType = it.key
                    val fundingEligibilityItem = it.value
                    val eligibility = fundingEligibilityItem.eligible
                    val reasons = fundingEligibilityItem.reasons
                    val eligibilityStatus = if (eligibility)
                            "is eligible" else "is not eligible"
                    Log.d(TAG,
                        "$paymentFundingType $eligibilityStatus. $reasons"
                    )
                }
            }
        }
        exception?.let { e ->
            Log.e(TAG, "Error", e)
        }
    }
)
```

#### Java

```text lineNumbers
paymentButtonContainer.setViewState(new PaymentButtonContainerViewState() {
    @Override
    public void onLoading() {
        Log.d(TAG, "Loading");
    }
    @Override
    public void onFinish(
            @Nullable FundingEligibilityState fundingEligibilityState,
            @Nullable Exception exception) {
        if (exception == null) {
            if (fundingEligibilityState != null &&
                    fundingEligibilityState.getPaymentsButtonMap() != null) {
                for (Map.Entry<PaymentFundingType, FundingEligibilityItem> entry:
                        fundingEligibilityState.getPaymentsButtonMap().entrySet()) {
                    PaymentFundingType paymentFundingType = entry.getKey();
                    FundingEligibilityItem fundingEligibilityItem = entry.getValue();
                    List<String> reasons = fundingEligibilityItem.getReasons();
                    Log.d(TAG, paymentFundingType
                                    + (fundingEligibilityItem.getEligible() ? " is" : " is not")
                                    + " eligible." ); for (String reason: reasons) { Log.d(TAG, reason); } } } } else { Log.e(TAG, "Error", exception); } }
});
```

If the call failed, then the `Exception` parameter will not be null. If the call succeeded, then the `FundingEligibilityState` parameter will not be null. The `FundingEligibilityState`contains a map of each `PaymentFundingType` available. This includes the default PayPal payment funding type as well as PayPal Credit and Pay Later. A `PaymentFundingType` may not be eligible for the buyer to use. The payment button for the funding type will not be visible if the funding type is not eligible.

**PaymentButtonContainer does not support PayPal Credit and Pay Later. Those buttons will return as not eligible.**

## Payment Buttons (Deprecated) [#payment-buttons-deprecated-1]

> **Note:** **Note:** `PayPalButton`, `PayPalCreditButton`, and `PayPalPayLaterButton`are deprecated in favor of `PaymentButtonContainer`. This section is provided as a reference to those using previous versions.

### Migrating to PaymentButtonContainer [#migrating-to-paymentbuttoncontainer-1]

* Replace `PayPalButton`, `PayPalCreditButton`, and `PayLaterButton` references with `PaymentButtonContainer` in your layout.

### Before [#before]

```javascript lineNumbers
<com.paypal.checkout.paymentbutton.PayPalButton
    android:id="@+id/payPalButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/margin_16x"
    android:tag="PayPal" />

<com.paypal.checkout.paymentbutton.PayPalCreditButton
    android:id="@+id/payPalCreditButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/margin_16x"
    android:tag="PayPal Credit" />

<com.paypal.checkout.paymentbutton.PayLaterButton
    android:id="@+id/payLaterButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/margin_16x"
    android:tag="Pay Later" />
```

### After [#after]

```java lineNumbers
<com.paypal.checkout.paymentbutton.PaymentButtonContainer
    android:id="@+id/payment_button_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:pay_later_button_color="silver"
    app:pay_later_button_enabled="true"
    app:pay_later_button_shape="pill"
    app:pay_later_button_size="medium"
    app:paypal_button_color="silver"
    app:paypal_button_enabled="true"
    app:paypal_button_label="pay"
    app:paypal_button_shape="rectangle"
    app:paypal_button_size="large"
    app:paypal_credit_button_color="black"
    app:paypal_credit_button_enabled="true"
    app:paypal_credit_button_shape="rounded"
    app:paypal_credit_button_size="small" />
```

Instead of setting up each payment button individually, you now only need to call `PaymentButtonContainer.setup()`.

### Before [#before-1]

```java lineNumbers
payPalButton.setup()
payLaterButton.setup()
payPalCreditButton.setup()
```

### After [#after-1]

```java lineNumbers
paymentButtonContainer.setup()
```

Instead of observing the `eligibilityStatus` for a payment button with `onEligibilityStatusChanged` in Kotlin or `paymentButtonEligibilityStatusChanged`in Java, use the `onLoading()` and `onFinish()` callbacks provided by the `PaymentButtonContainerViewState` for the `PaymentButtonContainer` as detailed in the `PaymentButtonContainerViewState` section above.

## Payment button [#payment-button]

The `PaymentButton` is the parent for all other buttons in the PayPal Mobile Checkout SDK for Android. The following attributes are available for use on every child button:

| Attribute              | Property | Description                                                                                                                                        |
| ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `payment_button_size`  | `size`   | Adjusts the minimum height of the button. The default value is `medium`, but can also be set to: `large` or `small`.                               |
| `payment_button_shape` | `shape`  | Overrides the shape of the button. The default shape derives from the theme of your app, but you can set it to: `pill`, `rectangle`, or `rounded`. |

### Payment button eligibility [#payment-button-eligibility-1]

To ensure buyers have an optimal experience, every `PaymentButton` adheres to strict eligibility requirements. Generally, the `PayPalButton` is always `Eligible` so it's safe to fallback for other buttons. The button offers functional and non-functional properties to observe on the status. For example:

#### Kotlin

```text lineNumbers
val paymentButton: PaymentButton //...
// Functional
paymentButton.onEligibilityStatusChanged = { buttonEligibilityStatus: PaymentButtonEligibilityStatus ->
    Log.i("PaymentButtonEligibility", "eligibility: $buttonEligibilityStatus")
}
// Non-functional
paymentButton.paymentButtonEligibilityStatusChanged = object : PaymentButtonEligibilityStatusChanged {
    override fun onPaymentButtonEligibilityStatusChanged(paymentButtonEligibilityStatus: PaymentButtonEligibilityStatus) {
        Log.i("PaymentButtonEligibility", "$paymentButton : $paymentButtonEligibilityStatus")
    }
}
```

#### Java

```text lineNumbers
paymentButton.setPaymentButtonEligibilityStatusChanged(new PaymentButtonEligibilityStatusChanged() {
    @Override
    public void onPaymentButtonEligibilityStatusChanged(@NotNull PaymentButtonEligibilityStatus paymentButtonEligibilityStatus) {
        Log.i("PaymentButtonEligibility", String.format("paymentButton : %s", paymentButtonEligibilityStatus));
    }
});
```

Both properties emit one value at a minimum, as the current value is emitted when either property is set. This is useful because the SDK retrieves funding eligibility requirements as soon as `PayPalCheckout.setConfig` is invoked. Usually, the funding eligibility retrieves by the time the `PaymentButton` renders. If funding eligibility isn't retrieved, the buttons are disabled and display a loading state.

You can also retrieve the current status through the `eligibilityStatus` property. The following are possible values:

| Status       | Description                                                                                                                              |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `Eligible`   | The button is visible and enabled, so buyers can interact with it.                                                                       |
| `Error`      | The button is disabled and the visibility is set hidden. This status only returns if there's an error retrieving the eligibility status. |
| `Ineligible` | The button is disabled and the visibility is set to hidden.                                                                              |
| `Loading`    | The button is visible, but disabled and displaying a loading indicator.                                                                  |

## PayPal button [#paypal-button-2]

| Attribute      | Property | Description                                                                                                                                                                              |
| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `paypal_color` | `color`  | Changes the background color of the button and adjusts the wordmark color to be visible. The default value is `gold`, but you can also set it to: `black`, `blue`, `silver`, or `white`. |
| `paypal_label` | `label`  | Adds a label on the button itself. The default value is no label, which is set with `paypal`, but you can also set it to: `checkout`, `buy_now`, or `pay`.                               |

## Pay Later button [#pay-later-button-2]

The `PayLaterButton` overrides the `PayPalButton` and always displays the Pay Later branding on the button as a label. You can't modify the `label`, but you can change the `color`to any color available for the `PayPalButton`.

## PayPal Credit button [#paypal-credit-button-2]

| Attribute             | Property | Description                                                                                                                  |
| --------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `paypal_credit_color` | `color`  | Changes the background color of the button and adjusts the wordmark to be visible. You can set it to `dark_blue` or `black`. |

## Custom UI [#custom-ui-1]

If you use a custom UI to launch the PayPal Checkout experience, you need to programmatically start the PayPal Mobile Checkout SDK.

## Launch the SDK from an activity [#launch-the-sdk-from-an-activity]

1. Register all callbacks to the `onCreate()` method of your activity (or to the `onAttach()`method of your fragment). This enables you to listen to certain key events in the checkout process, such as order approvals, orders cancellations, or errors.

   > **Note:** **Note:** If the activity is destroyed or re-created, you must register the callbacks again.

#### Kotlin

```text lineNumbers
class YourActivity: Activity {
    override fun onCreate(savedInstanceState: Bundle?) {
        PayPalCheckout.registerCallbacks(
            onApprove = OnApprove { approval ->
                // Optional callback for when an order is approved
            },
            onCancel = OnCancel {
                // Optional callback for when a buyer cancels the paysheet
            },
            onError = OnError { errorInfo ->
                // Optional error callback
            },
            onShippingChange = OnShippingChange { shippingChangeData, shippingChangeActions ->
                // Optional onShippingChange callback.
            }
        )
        setupButtons()
    }
}
```

#### Java

```text lineNumbers
public class YourActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        PayPalCheckout.registerCallbacks(
            approval -> {
                // Order is approved
            },
            () -> {
                // Optional callback for when a buyer cancels the order
            },
            errorInfo -> {
                // Optional error callback
            });
        setupButtons();
    }
}
```

2. Launch the PayPal Checkout process by invoking `PayPalCheckout.startCheckout(createOrderActions -> {});` when users select your custom UI button.

This sample code creates an order of a single item for $10.00 USD.

#### Kotlin

```text lineNumbers
PayPalCheckout.startCheckout(
    CreateOrder { createOrderActions ->
        val order = OrderRequest(
            intent = OrderIntent.CAPTURE,
            appContext = AppContext(
                userAction = UserAction.PAY_NOW
            ),
            purchaseUnitList = listOf(
                PurchaseUnit(
                    amount = Amount(
                        currencyCode = CurrencyCode.USD,
                        value = "10.00"
                    )
                )
            )
        )
        createOrderActions.create(order)
    }
)
```

#### Java

```text lineNumbers
PayPalCheckout.startCheckout(
    createOrderActions -> {
        ArrayList purchaseUnits = new ArrayList<>();
        purchaseUnits.add(
            new PurchaseUnit.Builder()
                .amount(
                    new Amount.Builder()
                        .currencyCode(CurrencyCode.USD)
                        .value("10.00")
                        .build()
                )
            .build()
        );
        OrderRequest order = new OrderRequest(
            OrderIntent.CAPTURE,
            new AppContext.Builder()
                .userAction(UserAction.PAY_NOW)
                .build(),
            purchaseUnits
        );
        createOrderActions.create(order, orderId -> {});
    }
);
```

## Launch the SDK from a ViewModel [#launch-the-sdk-from-a-viewmodel]

1. Register all callbacks in the ViewModel constructor.

   > **Note:** **Note:** Don't reference UI objects in your callbacks that might get destroyed by Android.

#### Kotlin

```text lineNumbers
class MyViewModel: ViewModel() {
    val _message = MutableLiveData<String>()
    val message: LiveData<String>
        get() =_message
    init {
        PayPalCheckout.registerCallbacks(
            onApprove = OnApprove { approval ->
                _message.value = "Order approved"
            },
            onCancel = OnCancel {
                _message.value = "Order cancelled"
            },
            onError = OnError { errorInfo ->
                _message.value = "Error creating order"
            }
        )
    }
}
```

#### Java

```text lineNumbers
public class MyViewModel extends ViewModel {
    private MutableLiveData<String> message = new MutableLiveData<>();
    public LiveData<String> getMessage() {
        return message;
    }
    public MyViewModel() {
        PayPalCheckout.registerCallbacks(
            approval -> {
                message.setValue("Order approved");
            },
            () -> {
                message.setValue("Order cancelled");
            },
            errorInfo -> {
                message.setValue("Error creating order");
            }
        );
    }
}
```

2. Launch the PayPal Checkout process by invoking a method in your ViewModel when users select your custom UI button.

Our example receives a list of items to add to the order.

#### Kotlin

```text lineNumbers
class MyViewModel: ViewModel() {
    ...
    fun startCheckout(items: List<PurchaseUnit>) {
        PayPalCheckout.startCheckout(
            CreateOrder { createOrderActions ->
                val order = OrderRequest(
                    intent = OrderIntent.CAPTURE,
                    appContext = AppContext(
                        userAction = UserAction.PAY_NOW
                    ),
                    purchaseUnitList = items
                )
                createOrderActions.create(order)
            }
        )
    }
}
```

#### Java

```text lineNumbers
public class MyViewModel extends ViewModel {
    ...
    public void startCheckout(List<PurchaseUnit> items) {
        PayPalCheckout.startCheckout(
            createOrderActions -> {
                ArrayList purchaseUnits = new ArrayList<>();
                purchaseUnits.add(items);
                OrderRequest order = new OrderRequest(
                    OrderIntent.CAPTURE,
                    new AppContext.Builder()
                        .userAction(UserAction.PAY_NOW)
                        .build(),
                    purchaseUnits
                );
                createOrderActions.create(order, orderId -> {
                });
            }
        );
    }
}
```

## Next Step [#next-step]

[Server-side integration](/limited-release/paypal-mobile-checkout/server-integration/)
