Overview
The Bolt iOS SDK provides a managed checkout flow that handles the entire payment experience β shipping, payment entry, and order completion. To launch checkout, your backend generates an order token and your app passes it to the SDK.
The SDK offers three levels of integration, from simplest to most explicit:
| Approach | Best For |
|---|---|
| Completion handler | Simplest β works from anywhere, including SwiftUI. |
| Delegate pattern | Callback-based, mirrors the Android SDK. |
| View controller | Full control over presentation. |
Generating an Order Token (Backend)
Before launching the checkout UI, your backend server must create an order token by calling the Bolt Merchant Orders API. This token represents the cart and is required by the SDK to start checkout.
WARNING
The API key used to authenticate this request is a secret. This call must be made from your server β never from the mobile app.
Request
POST https://api.bolt.com/v1/merchant/orders
Content-Type: application/json
X-Api-Key: <YOUR_MERCHANT_API_KEY>
| Environment | Endpoint |
|---|---|
| Sandbox | https://api-sandbox.bolt.com/v1/merchant/orders |
| Production | https://api.bolt.com/v1/merchant/orders |
Request Body
All amounts are in cents (e.g. 1783 = $17.83).
{
"cart": {
"order_reference": "your-unique-order-id",
"display_id": "ORDER-1234",
"currency": "USD",
"total_amount": 1783,
"tax_amount": 0,
"items": [
{
"name": "Cotton T-Shirt",
"reference": "SKU-001",
"description": "Comfortable cotton tee",
"sku": "SKU-001",
"total_amount": 1930,
"unit_price": 965,
"quantity": 2,
"type": "unknown",
"tax_amount": 0,
"image_url": "https://example.com/tshirt.jpg"
}
],
"shipments": [
{
"cost": 103,
"service": "Standard Shipping"
}
],
"discounts": [
{
"amount": 250,
"type": "discount"
}
]
}
}
Response
{
"token": "bolt-order-token-abc123"
}
Your backend returns this token to your mobile app, which then passes it to the SDK.
End-to-End Flow
βββββββββββββββ ββββββββββββββββββββ ββββββββββββ
β Mobile App βββ(1)βββΆβ Your Backend βββ(2)βββΆβ Bolt API β
β β β β β β
β ββββ(3)βββ (API key stays ββββ(3)βββ β
β β β server-side) β β β
β β ββββββββββββββββββββ ββββββββββββ
β β
β (4) Pass token to BoltCheckout.shared.startCheckout(...)
β β
β (5) SDK opens checkout UI β user completes payment
β β
β (6) Receive result via completion handler or delegate
βββββββββββββββ
- User taps “Checkout” β app sends cart details to your backend.
- Your backend calls
POST /v1/merchant/orderswith the cart and your API key. - Bolt returns the order token; your backend forwards it to the app.
- App passes the token to the SDK.
- SDK presents the checkout experience.
- App receives the result (success, cancelled, or failed).
Option A: Completion Handler (Simplest)
The SDK automatically finds the topmost view controller and presents the checkout. No UIViewController reference needed β works from anywhere, including SwiftUI.
import BoltInternal
func onCheckoutButtonTapped() {
let config = BoltCheckoutConfig(
orderToken: "order-token-from-your-backend",
hints: Bolt.Hints(
firstName: "",
lastName: "",
email: "",
phone: "",
phoneCountryCode: nil,
addressLine1: "",
addressLine2: nil,
city: "",
state: "",
zip: "",
country: "", // ISO 3166-1 alpha-2 code, e.g. "US"
companyName: "" // Optional
)
)
BoltCheckout.shared.startCheckout(config: config) { outcome in
switch outcome {
case .success(let result):
print("Order completed: \(result.orderReference)")
print("Transaction: \(result.transactionReference)")
case .canceled:
print("User canceled")
case .failed(let errorReason):
print("Error: \(errorReason)")
}
}
}
Option B: Delegate Pattern
Implement BoltSimpleCheckoutDelegate for callback-based results. This approach mirrors the Android SDK’s delegate pattern.
import BoltInternal
class CheckoutManager: BoltSimpleCheckoutDelegate {
func startCheckout(orderToken: String) {
let config = BoltCheckoutConfig(orderToken: orderToken)
BoltCheckout.shared.startCheckout(config: config, delegate: self)
}
// --- BoltSimpleCheckoutDelegate ---
func onCheckoutSuccess(result: BoltCheckoutResult) {
// result.reference β transaction reference
// result.status β transaction status
// result.amount β BoltAmountView (minor units, currency, symbol)
// result.cart?.orderReference β Bolt order reference
// result.merchantOrderNumber β your merchant order number
}
func onCheckoutError(errorReason: String) {
// Handle SDK, network, or validation errors
}
func onCheckoutCancel() {
// User dismissed checkout β return to cart
}
}
Option C: Present a View Controller Directly
For explicit control over presentation, use BoltCheckoutViewController:
let config = BoltCheckoutConfig(orderToken: "order-token-from-your-backend")
let checkoutVC = BoltCheckoutViewController(config: config, delegate: self)
present(checkoutVC, animated: true)
The view controller manages its own navigation and dismisses itself when checkout completes, cancels, or fails β your delegate receives the result.
Pre-Filling Customer Data
Use Bolt.Hints to pre-fill customer details and reduce friction during checkout:
| Field | Type | Description |
|---|---|---|
firstName |
String |
Customer’s first name. |
lastName |
String |
Customer’s last name. |
email |
String |
Customer’s email address. |
phone |
String |
Customer’s phone number. |
phoneCountryCode |
String? |
Phone country code (optional). |
addressLine1 |
String |
Street address line 1. |
addressLine2 |
String? |
Street address line 2 (optional). |
city |
String |
City. |
state |
String |
State or region. |
zip |
String |
Postal code. |
country |
String |
ISO 3166-1 alpha-2 country code (e.g. "US"). |
companyName |
String |
Optional company name. |
UI Modes
Currently, the SDK supports WebView mode only. The checkout experience is rendered via a Bolt-hosted WebView. Native checkout mode is planned for a future release.