# Custom Checkout

> Build a custom checkout experience using the Bolt Android SDK's payment flow and authorization APIs.

Source: https://help.boltapp.com/developers/sdks/android-kotlin/custom-checkout

## Overview [#overview]

If you need more control over the checkout experience than the [managed checkout flow](/developers/sdks/android-kotlin/checkout/) provides, you can use the SDK's **payment flow** and **payment authorization** APIs independently. This lets you:

1. **Collect a payment method**: Present the Bolt payment UI to tokenize a credit/debit card.
2. **Authorize the payment**: Charge the tokenized card against an order token on your terms.

This approach is useful when you want to tokenize and store a card for later use, or build a fully custom checkout UI around Bolt's payment infrastructure.

## Complete Example [#complete-example]

```kotlin title="Kotlin"
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import com.bolt.checkout.BoltCheckout
import com.bolt.checkout.intl.BoltPaymentFlowDelegate
import com.bolt.checkout.intl.BoltPaymentAuthorizationDelegate
import com.bolt.checkout.intl.BoltPaymentMethod
import com.bolt.checkout.intl.BoltCreditCard
import com.bolt.checkout.model.BoltCheckoutUserInfo

class CustomCheckoutActivity : ComponentActivity(),
    BoltPaymentFlowDelegate,
    BoltPaymentAuthorizationDelegate {

    private lateinit var paymentLauncher: ActivityResultLauncher<Intent>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        paymentLauncher = BoltCheckout.get().getPaymentFlowActivityResultLauncher(
            activity = this,
            boltPaymentFlowDelegate = this,
        )
    }

    fun onAddPaymentClicked() {
        BoltCheckout.get().startPaymentFlow(
            context = this,
            paymentFlowActivityLauncher = paymentLauncher,
        )
    }

    // --- BoltPaymentFlowDelegate ---

    override fun onPaymentFlowSuccess(
        paymentFlowMethod: BoltPaymentMethod,
        creditCard: BoltCreditCard?
    ) {
        // Card is now tokenized: show card summary in your UI
        creditCard?.let { showCardSummary(it.last4, it.network, it.expirationDate) }
    }

    override fun onPaymentFlowError(errorReason: String) {
        showError(errorReason)
    }

    override fun onPaymentFlowCancel() {
        // User backed out
    }

    // Called when the user confirms the order in your custom UI
    fun onConfirmOrder(orderToken: String) {
        BoltCheckout.get().authorizePayment(
            boltCheckoutUserInfo = BoltCheckoutUserInfo(
                firstName = "Jane",
                lastName = "Doe",
                email = "jane@example.com",
                phoneNumber = "+15551234567",
            ),
            orderToken = orderToken,
            boltPaymentAuthorizationDelegate = this,
        )
    }

    // --- BoltPaymentAuthorizationDelegate ---

    override fun onPaymentAuthorizationSuccess(orderReference: String) {
        navigateToConfirmation(orderReference)
    }

    override fun onPaymentAuthorizationFail(status: String, reason: String) {
        showDeclinedMessage(reason)
    }

    override fun onPaymentAuthorizationError(errorReason: String) {
        showError(errorReason)
    }
}
```

## Step-by-Step Breakdown [#step-by-step-breakdown]

### 1. Register the Payment Flow Launcher [#1-register-the-payment-flow-launcher]

Register an `ActivityResultLauncher` in your activity's `onCreate()`:

```kotlin title="Kotlin"
paymentLauncher = BoltCheckout.get().getPaymentFlowActivityResultLauncher(
    activity = this,
    boltPaymentFlowDelegate = this,
)
```

### 2. Launch the Payment Flow [#2-launch-the-payment-flow]

Present the Bolt payment UI to collect and tokenize a card:

```kotlin title="Kotlin"
BoltCheckout.get().startPaymentFlow(
    context = this,
    paymentFlowActivityLauncher = paymentLauncher,
)
```

On success, `onPaymentFlowSuccess` is called with a `BoltCreditCard` containing the tokenized card details (token, last4, network, expiration, postal code).

### 3. Authorize the Payment [#3-authorize-the-payment]

Once the user confirms in your custom UI, authorize the charge:

```kotlin title="Kotlin"
BoltCheckout.get().authorizePayment(
    boltCheckoutUserInfo = BoltCheckoutUserInfo(
        firstName = "Jane",
        lastName = "Doe",
        email = "jane@example.com",
        phoneNumber = "+15551234567",
    ),
    orderToken = orderToken,
    boltPaymentAuthorizationDelegate = this,
)
```

<Warning>
  If `authorizePayment()` is called before a card has been tokenized via the payment flow, `onPaymentAuthorizationError` fires immediately with an explanatory message.
</Warning>

## Payment Flow Callbacks [#payment-flow-callbacks]

See the full [BoltPaymentFlowDelegate reference](/developers/sdks/android-kotlin/api-reference/#boltpaymentflowdelegate).

| Callback                                              | Description                                                                                            |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `onPaymentFlowSuccess(paymentFlowMethod, creditCard)` | Card successfully tokenized. `creditCard` contains token, last4, network, expiration, and postal code. |
| `onPaymentFlowError(errorReason)`                     | Tokenization or network failure.                                                                       |
| `onPaymentFlowCancel()`                               | User dismissed the payment screen.                                                                     |

## Payment Authorization Callbacks [#payment-authorization-callbacks]

See the full [BoltPaymentAuthorizationDelegate reference](/developers/sdks/android-kotlin/api-reference/#boltpaymentauthorizationdelegate).

| Callback                                        | Description                                                            |
| ----------------------------------------------- | ---------------------------------------------------------------------- |
| `onPaymentAuthorizationSuccess(orderReference)` | Payment authorized. Use `orderReference` to confirm with your backend. |
| `onPaymentAuthorizationFail(status, reason)`    | Authorization declined by the processor (e.g. insufficient funds).     |
| `onPaymentAuthorizationError(errorReason)`      | Request failed before reaching the processor (e.g. network timeout).   |
