# Kustom Checkout in an iOS app

Add Kustom Checkout to an iOS app with KustomMobileSDK — install with Swift Package Manager or CocoaPods, create a KustomCheckoutView and handle its events.

This guide adds Kustom Checkout to an iOS app with the Kustom Mobile SDK. You create a
`KustomCheckoutView`, set the checkout snippet your server returns on it, and handle the
events it dispatches. [Kustom Checkout in a mobile app](/checkout/mobile-sdk/) explains what's
common to every platform.

## Before you start

You need:

- **A server endpoint that returns a checkout snippet.** Your backend, not the app, creates
  the order with your API credentials and returns its `html_snippet`. See [Create and update
  an order](/checkout/integrate/create-order/). This guide calls the endpoint `<YOUR-URL>`.
- **A return URL.** A custom URL scheme your app is registered for, such as `myapp://`. It
  brings the customer back after a payment method sends them to a third-party app. See [the
  return URL](/checkout/mobile-sdk/#the-return-url).

## Step by step

### 1. Add the SDK

**Swift Package Manager.** In Xcode, go to **File → Swift Packages → Add Package
Dependency** and enter the repository URL
`https://github.com/Kustom-Checkout/kustom-mobile-sdk-spm`. Under **Version**, choose **Up
to Next Major** and keep the default. Then select **KustomMobileSDK** in the **Package
Product** column.

**CocoaPods.** Add the dependency to your Podfile:

```ruby
pod "KustomMobileSDK"
```

Then install it:

```bash
pod install
```

Either way, you can now `import KustomMobileSDK` in your workspace.

### 2. Create the checkout view

The checkout view is `KustomCheckoutView`. Create it in your view controller with your return
URL and an event handler. The handler is any object that implements the `KustomEventHandler`
protocol (step 4):

```swift
var checkoutView: KustomCheckoutView?

override func viewDidLoad() {
    super.viewDidLoad()
    checkoutView = KustomCheckoutView(
        returnURL: URL(string: "myapp://")!,
        eventHandler: self
    )
}
```

### 3. Set the snippet

Fetch the `html_snippet` from `<YOUR-URL>` and set it on the view. This is what renders the
checkout:

```swift
checkoutView?.setSnippet(snippet)
```

### 4. Handle events and errors

Implement the two methods of `KustomEventHandler`. The first receives product events, the
second receives SDK errors:

```swift
func kustomComponent(_ component: KustomComponent, dispatchedEvent event: KustomProductEvent) {
    if event.action == "complete" {
        loadConfirmation(event.params["uri"])
    }
}

func kustomComponent(_ component: KustomComponent, encounteredError error: KustomMobileSDKError) {
    // If error.isFatal is set, the checkout can't continue
}
```

The `complete` action means the customer has paid, and `params["uri"]` is the confirmation
URL to load next. [Events and errors](/checkout/mobile-sdk/#events-and-errors) lists every
action and error field.

## Check that it works

Point the app at a Playground order and run the flow end to end:

1. The checkout renders in the view after `setSnippet`, rather than staying blank.
2. Paying with [Playground test data](/basics/test-data/) dispatches a `complete` event carrying a `uri`.
3. Your confirmation screen loads from that `uri`.
4. Turning off the network mid-checkout produces an error in `encounteredError`, with `isFatal` telling you whether to recover or bail out.

A blank view almost always means the snippet never arrived. Check the response from
`<YOUR-URL>` before suspecting the SDK.

## Variations

**Replacing the event handler.** Assign a new object that implements `KustomEventHandler`:

```swift
checkoutView?.eventHandler = handlerObject
```

**Sizing the view.** To control how the views inside `KustomCheckoutView` resize, implement
the `KustomSizingDelegate` protocol and set it on the view:

```swift
checkoutView?.sizingDelegate = listenerObject
```

**Pausing the checkout while you update the order.** `suspend()` stops the customer from
interacting with the checkout and `resume()` lets them continue. Suspend before you change the
order and resume afterwards, so the customer never sees stale totals:

```swift
checkoutView?.suspend()
checkoutView?.resume()
```

**Handling external payment methods yourself.** By default the SDK handles external payment
methods. To take that over, set this before the checkout starts, then act on the `external`
action, whose `params["uri"]` is where to send the customer:

```swift
checkoutView?.checkoutOptions.merchantHandlesEPM = true
```

**Handling validation errors yourself.** Set this before the checkout starts, then act on the
`validation_error` action, which carries `error_type` and `error_text`:

```swift
checkoutView?.checkoutOptions.merchantHandlesValidationErrors = true
```

## Troubleshooting

**The customer is left in the bank app after BankID.** BankID may not return the customer
automatically after authentication. They might have to switch back to your app themselves.

## Related

- [Confirmation and push](/checkout/integrate/confirmation-and-push/) — what your server must do once `complete` fires
- [Create and update an order](/checkout/integrate/create-order/) — the call behind `<YOUR-URL>`
- [Kustom Checkout in a mobile app](/checkout/mobile-sdk/) — native or hybrid, the return URL and migrating from the Klarna Mobile SDK
- [Android](/checkout/mobile-sdk/android/) and [React Native](/checkout/mobile-sdk/react-native/) — the same integration on the other platforms
- [Test data](/basics/test-data/) — Playground customers and cards to pay with
