# Shipping Options (/limited-release/paypal-mobile-checkout/shipping-options)



## iOS [#ios]

You can enable your buyers to update their shipping options during checkout. After adding the `OnShippingChange` callback to your integration, your buyers can:

* Enter a new shipping address.
* Select a local pickup option.
* Select different shipping services.
* Buy Online, Pick up In Store (BOPIS).

If a buyer updates their shipping options during checkout, the order must also update the `OnShippingChange` callback.

> **Note:** **Note:** In this documentation, we refer to both shipping and pickup as shipping option. The shipping option is represented by the object `ShippingMethod`.

### Create an Order with shipping options [#create-an-order-with-shipping-options]

You can add shipping options to either a client-side or server-side integration.

#### Client-side integration [#client-side-integration]

To provide shipping options to the buyer, add shipping options to the shipping object provided in the `OrderRequest` object and pass it inside the `createOrder` callback.

Make sure to have exactly one shipping option with `selected: true` as a default option. To support Buy Online, Pick up In Store (BOPIS) add only the `.pickup` shipping type `ShippingMethod` to the shipping options and set `selected: true`.

#### Swift

```text lineNumbers
createOrder: { action in
  let order = OrderRequest(
    intent: .authorize,
    purchaseUnits: [
      PurchaseUnit(
        amount: PurchaseUnit.Amount(currencyCode: .usd, value: "5.00"),
        shipping: PurchaseUnit.Shipping(
          options: [
            ShippingMethod(
              id: "SHIP_123",
              label: "2-day Shipping",
              selected: true,
              type: .shipping,
              amount: UnitAmount(currencyCode: .usd, value: "2.00")),
            ShippingMethod(
              id: "PICKUP_123",
              label: "Pickup in store",
              selected: false,
              type: .pickup,
              amount: UnitAmount(currencyCode: .usd, value: "0.00"))
        ],
      ),
      ),
    ],
    applicationContext: OrderApplicationContext(userAction: .payNow)
  )
  action.create(order: order)
}
```

#### Obj-C

```text lineNumbers
createOrder : ^(PPCCreateOrderAction *action) {
PPCPurchaseUnitAmount*purchaseUnitAmount =
      [[PPCPurchaseUnitAmount alloc] initWithCurrencyCode:PPCCurrencyCodeUsd
                                                    value:@"5.00"
                                                breakdown:nil];
  PPCShippingMethod *shipping = [[PPCShippingMethod alloc]
      initWithId:@"SHIP_123"
           label:@"2-day Shipping"
        selected:true
            type:PPCShippingTypeShipping
          amount:[[PPCUnitAmount alloc] initWithCurrencyCode:PPCCurrencyCodeUsd
                                                       value:@"2.00"]];
PPCShippingMethod*pickup = [[PPCShippingMethod alloc]
      initWithId:@"PICKUP_123"
           label:@"Pickup in Store"
        selected:false
            type:PPCShippingTypePickup
          amount:[[PPCUnitAmount alloc] initWithCurrencyCode:PPCCurrencyCodeUsd
                                                       value:@"0.00"]];
  PPCPurchaseUnitShipping *shippingOptions = [[PPCPurchaseUnitShipping alloc]
      initWithShippingName:nil
                   address:nil
                   options:@[ shipping, pickup ]];
PPCPurchaseUnit*purchaseUnit =
      [[PPCPurchaseUnit alloc] initWithAmount:purchaseUnitAmount
                                  referenceId:nil
                                        payee:nil
                           paymentInstruction:nil
                      purchaseUnitDescription:nil
                                     customId:nil
                                    invoiceId:nil
                               softDescriptor:nil
                                        items:nil
                                     shipping:shippingOptions];
  PPCOrderRequest *order =
      [[PPCOrderRequest alloc] initWithIntent:PPCOrderIntentAuthorize
                                purchaseUnits:@[ purchaseUnit ]
                                        payer:nil
                           applicationContext:nil];
  [action createWithOrder:order completion:nil];
}
```

For more information on how to implement the `createOrder` callback, refer to the [initialize SDK instructions](/limited-release/paypal-mobile-checkout/initialize-sdk/).

#### Server-side integration [#server-side-integration]

If you use a server-side integration, refer to the documentation for [Server-side integration](/limited-release/paypal-mobile-checkout/server-integration/) and use one of our APIs (NVP/SOAP, REST v1, or REST v2) to create an order with shipping options.

### Implement the `onShippingChange` callback [#implement-the-onshippingchange-callback]

Implement the `onShippingChange` callback to approve or reject a change a buyer makes to their shipping address or shipping option.

#### Add the `onShippingChange` callback [#add-the-onshippingchange-callback]

Depending on your integration, you need to add the `onShippingChange` callback to either the `PaymentButtonContainer` or `CheckoutConfig.init()` or `Checkout.start()`.

#### Standard integration [#standard-integration]

Add the `onShippingChange` callback to `PaymentButtonContainer`.

#### Swift

```text lineNumbers
let paymentButton = PaymentButtonContainer()
paymentButton.setup(
  ...
  onShippingChange: { change, action in
    ...
  }
)
```

#### Obj-C

```text lineNumbers
PPCPaymentButtonContainer *paymentButton = [[PPCPaymentButtonContainer alloc]
    initWithPayPalButtonUIConfiguration:[[PPCPayPalButtonUIConfiguration alloc]
                                            init]
      payPalCreditButtonUIConfiguration:[[PPCPayPalCreditButtonUIConfiguration
                                            alloc] init]
          payLaterButtonUIConfiguration:[[PPCPayLaterButtonUIConfiguration
                                            alloc] init]
                               delegate:self];
[paymentButton setupWithOnCreateOrder:......
onShippingChange:^(PPCShippingChange*change,
                                        PPCShippingChangeAction *action){
                         ...}];
}
```

#### Advanced integration [#advanced-integration]

If your integration programatically starts the SDK, you can add the `onShippingChange` callback to `CheckoutConfig.init()`.

#### Swift

```text lineNumbers
let config = CheckoutConfig(
  ...
  onShippingChange: { change, action in
    ...
  }
  ...
)
```

#### Obj-C

```text lineNumbers
PPCheckoutConfig *config = [[PPCheckoutConfig alloc]
    initWithClientID:......
onShippingChange:^(PPCShippingChange*change,
                       PPCShippingChangeAction *action){
        ...}...];
```

Or you can add the `onShippingChange` callback when starting the checkout paysheet. &#x2A;Note:* If you've already set the callback in `CheckoutConfig.init()`, setting it again here will overwrite the previous value. It is recommended that you only set it using one of these two ways.

#### Swift

```text lineNumbers
Checkout.start(
  ...
  onShippingChange: { change, action in
    ...
  }
  ...
)
```

#### Obj-C

```text lineNumbers
[PPCheckout
  startWithPresentingViewController:self...
    onShippingChange:^(PPCShippingChange *change,
PPCShippingChangeAction*action){
        ...}...];
```

### Approve address or shipping option changes [#approve-address-or-shipping-option-changes]

You can approve the update a buyer makes to their address or shipping option.

#### Swift

```text lineNumbers
onShippingChange: { change, action in
  action.approve()
},
onApprove: {},
onCancel: {},
onError: {}
```

#### Obj-C

```text lineNumbers
onShippingChange:^(PPCShippingChange *change, PPCShippingChangeAction*action) {
  [action approve];
},
onApprove: {},
onCancel: {},
onError: {}
```

### Reject address or shipping option changes [#reject-address-or-shipping-option-changes]

You can reject an update to an address or shipping option that is not supported. This displays an error to the buyer that requires them to change their shipping option or address in order to proceed.

#### Swift

```text lineNumbers
onShippingChange: { change, action in
  switch change.type {
    case .shippingAddress:
      if !yourSupportedListOfZipCode.contains(change.selectedShippingAddress.postalCode) {
        action.reject()
      }
    default:
      break
    }
}
```

#### Obj-C

```text lineNumbers
onShippingChange:^(PPCShippingChange *change, PPCShippingChangeAction*action) {
  switch (change.type){
    case PPCShippingChangeTypeShippingAddress:
      if (![yourSupportedListOfZipCode containsObject:change.selectedShippingAddress.postalCode]) {
        [action reject];
      }
    default:
      break
  }
}
```

## Android [#android]

You can enable your buyers to update their shipping options during checkout. After adding the `OnShippingChange` callback to your integration, your buyers can:

* Enter a new shipping address.
* Select a local pickup option.
* Select different shipping services.
* Buy Online, Pick up In Store (BOPIS).

If a buyer updates their shipping options during checkout, the order must also update the `OnShippingChange` callback.

> **Note:** **Note:** In this documentation, we refer to both shipping and pickup as shipping option. The shipping option is represented by the object `ShippingMethod`.

## Create an Order with shipping options [#create-an-order-with-shipping-options-1]

You can add shipping options to either a client-side or server-side integration.

#### Client-side integration [#client-side-integration-1]

To provide shipping options to the buyer, add shipping options to the shipping object provided in the `OrderRequest` object and pass it inside the `createOrder` callback.

Make sure to have exactly one shipping option with `.selected(true)` as a default option. To support Buy Online, Pick up In Store (BOPIS) add only the `ShippingType.PICKUP` shipping type `ShippingMethod` to the shipping options and set `.selected(true)`.

#### Kotlin

```text lineNumbers
val orderRequest: OrderRequest = OrderRequest.Builder()
  .intent(OrderIntent.AUTHORIZE)
  .purchaseUnitList(
    arrayListOf(
      PurchaseUnit.Builder()
        .amount(
          Amount.Builder()
            .value("5.00")
            .currencyCode(CurrencyCode.USD)
            .build()
        )
        .shipping(
          Shipping.Builder()
            .options(
              arrayListOf(
                Options.Builder()
                  .id("1")
                  .selected(true)
                  .label("Standard Shipping")
                  .type(ShippingType.SHIPPING)
                  .amount(
                    UnitAmount.Builder()
                      .currencyCode(CurrencyCode.USD)
                      .value("10.00")
                      .build()
                  ).build(),
                Options.Builder()
                  .id("2")
                  .selected(false)
                  .label("In store pickup")
                  .type(ShippingType.PICKUP)
                  .amount(
                    UnitAmount.Builder()
                      .currencyCode(CurrencyCode.USD)
                      .value("3.00")
                      .build()
                  ).build()
              )
            ).build()
        ).build()
    )
  ).build()
```

#### Java

```text lineNumbers
OrderRequest orderRequest = new OrderRequest.Builder()
  .intent(OrderIntent.AUTHORIZE)
  .purchaseUnitList(new ArrayList<>(List.of(
          new PurchaseUnit.Builder()
            .amount(new Amount.Builder()
              .value("5.00")
              .currencyCode(CurrencyCode.USD)
              .build()
            )
            .shipping(new Shipping.Builder()
              .options(new ArrayList<>(List.of(
                new Options.Builder()
                  .id("1")
                  .selected(true)
                  .label("Standard Shipping")
                  .type(ShippingType.SHIPPING)
                  .amount(new UnitAmount.Builder()
                    .currencyCode(CurrencyCode.USD)
                    .value("10.00")
                    .build()
                  ).build(),
                new Options.Builder()
                  .id("2")
                  .selected(false)
                  .label("In store pickup")
                  .type(ShippingType.PICKUP)
                  .amount(
                    new UnitAmount.Builder()
                      .currencyCode(CurrencyCode.USD)
                      .value("3.00")
                      .build()
                  ).build()
              ))).build()
            ).build()
  ))).build();
```

For more information on how to implement the `createOrder` callback, refer to the [initialize SDK instructions](/limited-release/paypal-mobile-checkout/initialize-sdk/).

#### Server-side integration [#server-side-integration-1]

If you use a server-side integration, refer to the documentation for [Server-side integration](/limited-release/paypal-mobile-checkout/server-integration/) and use one of our APIs (NVP/SOAP, REST v1, or REST v2) to create an order with shipping options.

### Implement the `onShippingChange` callback [#implement-the-onshippingchange-callback-1]

Implement the `onShippingChange` callback to approve or reject a change a buyer makes to their shipping address or shipping option.

#### Add the `onShippingChange` callback [#add-the-onshippingchange-callback-1]

Depending on your integration, you need to add the `OnShippingChange` callback to either the `paymentButtonContainer` or `PayPalCheckout.startCheckout()`.

#### Standard integration [#standard-integration-1]

Add the `OnShippingChange` callback to `PaymentButtonContainer`.

#### Kotlin

```text lineNumbers
paymentButtonContainer.setup(
    createOrder = CreateOrder {},
    onShippingChange = OnShippingChange { shippingChangeData, shippingChangeActions -> }
)
```

#### Java

```text lineNumbers
paymentButtonContainer.setup(
    createOrderActions -> {},
    approval -> {},
    (shippingChangeData, shippingChangeActions) -> {}
);
```

#### Advanced integration [#advanced-integration-1]

If your integration programatically starts the SDK, add the `OnShippingChange` callback to `PayPalCheckout.registerCallbacks()`.

#### Kotlin

```text lineNumbers
PayPalCheckout.registerCallbacks(
    onShippingChange = OnShippingChange { shippingChangeData, shippingChangeActions -> },
    onApprove = OnApprove {}, onCancel = OnCancel {}, onError = OnError {}
)
```

#### Java

```text lineNumbers
PayPalCheckout.registerCallbacks(
    approval -> {},
    (shippingChangeData, shippingChangeActions) -> { },
    (OnCancel) () -> {}, errorInfo -> {}
);
```

### Approve address or shipping option changes [#approve-address-or-shipping-option-changes-1]

You can approve the update a buyer makes to their address or shipping option.

#### Kotlin

```text lineNumbers
PayPalCheckout.registerCallbacks(
    onShippingChange = OnShippingChange { shippingChangeData, shippingChangeActions ->
        shippingChangeActions.approve()
    },
    onApprove = OnApprove {},
    onCancel = OnCancel {},
    onError = OnError {}
)
```

#### Java

```text lineNumbers
PayPalCheckout.registerCallbacks(
    approval -> {},
    (shippingChangeData, shippingChangeActions) -> shippingChangeActions.approve(),
    () -> {}, errorInfo -> {}
);
```

### Reject address or shipping option changes [#reject-address-or-shipping-option-changes-1]

You can reject an update to an address or shipping option that is not supported. This displays an error to the buyer that requires them to change their shipping option or address in order to proceed.

#### Kotlin

```text lineNumbers
OnShippingChange { shippingChangeData, shippingChangeActions ->
    when (shippingChangeData.shippingChangeType) {
        ShippingChangeType.ADDRESS_CHANGE -> {
            // Example - Reject all shipping addresses outside of the US
            if (shippingChangeData.shippingAddress.countryCode != "US") {
                shippingChangeActions.reject()
            }
        }
    }
}
```

#### Java

```text lineNumbers
(shippingChangeData, shippingChangeActions) -> {
    switch (shippingChangeData.getShippingChangeType()) {
        case ADDRESS_CHANGE:
        // Example - Reject all shipping addresses outside of the US
        if (!Objects.equals(shippingChangeData.getShippingAddress().getCountryCode(), "US")) {
            shippingChangeActions.reject();
        }
    }
}
```
