> This page is for version v2 (default).
> For other versions, use one of these documentation indexes:
> - v2 (default): https://developers.clearpay.co.uk/v-2/llms.txt
> - v1: https://developers.clearpay.co.uk/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.clearpay.co.uk/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.clearpay.co.uk/_mcp/server.

# Integrated Shipping

This feature improves the user experience by embedding your shipping options directly into the Clearpay Express Checkout flow. It streamlines the checkout process and can be combined with the `buyNow` flag to create a one-stop checkout that immediately precedes the order confirmation page.

We recommend the **Integrated Shipping** flow for merchants with:

* Fewer than 5 shipping options
* Single shipping option for an entire order (i.e. no SKU level options)
* Simple tiered shipping options (e.g. standard, express, rush)
* Pickup in-store option before checkout entry

Multiple button styles are available, each clearly communicating the next step to the customer.

![](/_fern-img/5fdef626bec0a3e068a7a83c959d8883dd333c2328d1195e700b6aebb199d708.webp)

Integrated Shipping is configured in the call to **initializeForPopup** triggered by the Express Checkout button.

It requires `shippingOptionRequired` to be true (enabled by default) and an **onShippingAddressChange** callback must be defined:

```javascript
AfterPay.initializeForPopup({
  // ...
  shippingOptionRequired: true,
  onShippingAddressChange: function (data, actions) {
    /* address in `data` */
    /* calc options, then call `actions.resolve(options)` */
  },
});
```

## Full Example with Integrated Shipping

```javascript
AfterPay.initializeForPopup({
  countryCode: 'GB',
  onCommenceCheckout: function(actions) {
    /* retrieve afterpay token from your server */
    /* then call `actions.resolve(token)` */
  },
  onShippingAddressChange: function (data, actions) {
    /* required for Integrated Shipping  */
    /* address in `data` */
    /* calc options, then call `actions.resolve(options)` */
  },
  onShippingOptionChange: function (data) {
    /* optional - chosen option in `data` */
  },
  onComplete: function (data) {
    /* handle success/failure of checkout */
  },
  target: '#clearpay-express-button',
  buyNow: false,
  pickup: false,
  shippingOptionRequired: true
})
```

> **Note**
>
> Integrated Shipping is enabled by default for Express orders. To disable it, `shippingOptionRequired` must be set to false.

## Restrictions

Integrated Shipping requires the Express Checkout flow to be launched as a popup, due to the way shipping information is communicated over the frontend. The redirect method is not supported.

## Listening for Address Changes

The Shipping Address Change callback is a feature of the Express Checkout. This callback allows a merchant to dynamically update shipping options and taxes based on the shipping address chosen by the consumer.

The shipping address change callback is required:

* If you intend to update the order total based on a chosen shipping address.
* To validate that you can ship to the selected address.

To set up the Shipping Address Change callback, implement the **onShippingAddressChange** function. This function will be passed two arguments: \*\*data \*\*and **actions**.

How the shipping options are calculated is entirely managed by the merchant. They can be calculated in Javascript or by handing off to an internal API.

If shipping options are available for the given address, they can be returned to Clearpay using the resolve action as shown in the code example below. Similarly, the reject action is used when shipping is unavailable.

**Example retrieving shipping options via API**

```javascript
AfterPay.initializeForPopup({
  // ...
  onShippingAddressChange: function (data, actions) {
    fetch('/your-shipping-endpoint', {
      method: 'POST',
      headers: { 'content-Type': 'application/json' },
      body: JSON.stringify(data),
    }).then(function(options) {
      actions.resolve(options)
    }).catch(function(error) {
      // Parse the response and send an AfterPay rejection, e.g.:
      actions.reject(AfterPay.CONSTANTS.SHIPPING_UNSUPPORTED)
    })
  },
})
```

**Example calculating shipping options in JS**

```javascript
AfterPay.initializeForPopup({
  // ...
  onShippingAddressChange: function (data, actions) {
    if (data.countryCode !== 'GB') {
      // Reject any unsupported shipping addresses
      actions.reject(AfterPay.CONSTANTS.SHIPPING_UNSUPPORTED)
    } else {
      // Calc shipping inline
      actions.resolve([ {
        id: '1', name: 'Standard', description: '3 - 5 days',
        shippingAmount: { amount: '0.00', currency: 'GBP'},
        taxAmount: { amount: '3.18', currency: 'GBP'},
        orderAmount: { amount: '34.99', currency: 'GBP'},
      }, {
        id: '2', name: 'Priority', description: 'Next business day',
        shippingAmount: { amount: '10.99', currency: 'GBP'},
        taxAmount: { amount: '4.28', currency: 'GBP'},
        orderAmount: { amount: '47.08', currency: 'GBP'},
      } ])
    }
  },
})
```

Clearpay calls your **onShippingAddressChange** function when:

* The consumer first enters the Clearpay summary page
* The consumer makes a change to their shipping address on the Clearpay summary page

Clearpay provides the following parameters to your **onShippingAddressChange** function:

* **data** parameter: This contains the consumer’s selected address with fields:
  * `name`, `phoneNumber`, `address1`, `address2`, `area2`, `suburb`, `state`, `postcode` and `countryCode`

* **action** parameter: This object is used to return your response to the Clearpay checkout. It consists of the following methods:
  * `resolve` : Call this method to provide the shipping options applicable to the consumers address. Takes an array of **Shipping Option** objects.
  * `reject` : Call this method when you are unable to handle the request. Do not throw an error, instead call this method with a **Shipping Constant** as the first argument to indicate a status, e.g.:

```html
actions.reject(AfterPay.CONSTANTS.SHIPPING_UNSUPPORTED)
```

## Shipping Option Model

| Attribute        | Type              | Description                                                 |
| :--------------- | :---------------- | :---------------------------------------------------------- |
| `id`             | String (required) | A shipping option identifier. Max length 128                |
| `name`           | String (required) | The name of the shipping options                            |
| `shippingAmount` | Money (required)  | The shipping amount (without tax, if including `taxAmount`) |
| `taxAmount`      | Money (required)  | The tax amount                                              |
| `orderAmount`    | Money (required)  | The total amount for the order including shipping and taxes |
| `description`    | String            | A description for this shipping option                      |

## Shipping Constants

To indicate a number of error scenarios, `actions.reject()` may be invoked with a provided constant.

These are of the form `AfterPay.constants.<NAME>`, where `<NAME>` is one of:

| Constant                        | Description                                 |
| :------------------------------ | :------------------------------------------ |
| `SHIPPING_ADDRESS_UNRECOGNIZED` | Unrecognized address                        |
| `SHIPPING_ADDRESS_UNSUPPORTED`  | Recognized address, but will not ship there |
| `SERVICE_UNAVAILABLE`           | General service error.                      |

> **Warning**
>
> Clearpay Express Checkout does not perform any arithmetic. It is the responsibility of your web app to calculate the correct total. Each shipping option must have a total order amount including taxes and shipping.

## Listening for Shipping Option Changes

The `onShippingOptionChange` callback allows a merchant to track the user’s chosen shipping option as it changes. It is optional, and will be called each time a user selects a shipping option. This function is passed one argument: **data**

**data** parameter (object): This contains the consumer’s selected shipping option, as provided in the response from onShippingAddressChange, with fields:

| ID   | Name   | Description   | Shipping Amount  | Order Amount  |
| :--- | :----- | :------------ | :--------------- | :------------ |
| `id` | `name` | `description` | `shippingAmount` | `orderAmount` |

```javascript
AfterPay.initializeForPopup({
  // ...
  onShippingOptionChange: function (data) {
    console.log(data)
  },
})
```

## Listening for Warning/Error messages

To facilitate handling of logging/warning/error messages, `AfterPay.onMessage` can optionally be replaced with a custom function. The default function is:

## Buy Now

When the Express Checkout is complete, you may either call the `Auth` endpoint immediately or continue checkout on your review page. If you are authorizing (or capturing) payment immediately, set the `buyNow` flag to true - this shows the user a “Buy Now” button at the end of their Clearpay journey.

```html
AfterPay.initializeForPopup({
  // ...
  buyNow: true,
})
```

![](file:docs/assets/images/580be7b-Buy_now2.png "Buy now2.png")

## Configuring a pickup order

The Express Checkout experience can be tailored for Click & Collect and other pickup flows by following these steps:

1. Allow your users the ability to choose pickup options before they select Clearpay Express. This should include any decisions that may impact the cost of delivery, for instance pickup location and date.
2. If the user has opted for pickup, provide the chosen pickup address when creating the order via the `shipping` body parameter -- e.g

```curl
curl --request POST \
  --url https://api.eu-sandbox.afterpay.com/v2/checkouts \
  --header 'accept: application/json' \
  --header 'content-type: application/json' \
  --data '{"amount":{"amount":"10.00", “currency”: “GBP”}, “mode”: “express”, "merchant": {"popupOriginUrl": "https://example.com"}, "shipping": {"name": "Your Store Name", "line1": "123 Store Address", "postcode": "0000"}}'
```

3. When invoking `initializeForPopup`

* Set the pickup flag to true.
* Configure your onShippingAddressChange handler to return the name and description of their pickup choice. This will likely mean returning only a single option -- e.g

```javascript
actions.resolve([ {
  id: 'pickup-store-123', name: 'Click & Collect',
  description: 'Available for next-day pickup',
  shippingAmount: { amount: '0.00', currency: 'GBP'},
  taxAmount: { amount: '3.18', currency: 'GBP'},
  orderAmount: { amount: '34.99', currency: 'GBP'},
} ])
```

Depending on your configuration, your frontend may have already invoked `initializeForPopup` before knowing whether the user will opt for pickup.\
It is safe to invoke `initializeForPopup` multiple times; each call will overwrite the previous settings. In this case you may choose to call `initializeForPopup` in response to the user selecting a pickup option.

4. You may choose to collect additional information regarding the pickup, e.g. electing another person to pick up the order, at your order review page. These details must not affect the order total.