Recipe
- Web
- Android
- iOS
checkout.addEventListener('primer:ready', (event) => {
const primer = event.detail;
primer.onPaymentSuccess = ({ payment, paymentMethodType }) => {
const message = `Payment of ${payment.amount} completed via ${paymentMethodType}`;
showSuccessModal(message);
};
});
val state by checkout.state.collectAsStateWithLifecycle()
LaunchedEffect(state) {
when (val s = state) {
is PrimerCheckoutState.Success -> {
val payment = s.checkoutData.payment
Log.d("Checkout", "Payment completed: ${payment.id}")
navController.navigate("confirmation/${payment.id}") {
popUpTo("checkout") { inclusive = true }
}
}
is PrimerCheckoutState.Failure -> {
val error = s.error
Log.e("Checkout", "Failed: ${error.description}")
Log.e("Checkout", "Diagnostics: ${error.diagnosticsId}")
}
else -> Unit
}
}
PrimerCheckoutSheet(checkout = checkout)
struct CheckoutView: View {
let clientToken: String
@State private var showSuccess = false
var body: some View {
ZStack {
PrimerCheckout(
clientToken: clientToken,
onCompletion: { state in
if case .success = state {
withAnimation { showSuccess = true }
}
}
)
if showSuccess {
SuccessOverlay()
.transition(.opacity)
}
}
}
}
How it works
- Web
- Android
- iOS
- Listen for the
primer:readyevent to access the Primer SDK instance - Set the
onPaymentSuccesscallback - Access
paymentdetails andpaymentMethodTypefrom the callback parameters - Display your custom UI (modal, toast, inline message, etc.)
- Observe
checkout.statewithcollectAsStateWithLifecycle()and react in aLaunchedEffect - Handle
PrimerCheckoutState.Successto accessPrimerCheckoutDatawith payment details - Navigate to a confirmation screen or update your order UI
| Property | Type | Description |
|---|---|---|
payment.id | String | The Primer payment ID |
payment.orderId | String? | Your order ID |
When using
PrimerCheckoutSheet, the SDK shows a default success screen that auto-dismisses after 3 seconds. The Success state emits immediately — you do not need to wait for the dismiss. Navigate as soon as you observe the state.- Use the
onCompletioncallback onPrimerCheckout - Match on
.successto detect payment completion - Access
result.paymentIdfor the payment ID - Update your SwiftUI state to show a custom success view
Variations
Custom success with payment details
- Web
- Android
- iOS
primer.onPaymentSuccess = ({ payment }) => {
document.getElementById('success-container').innerHTML = `
<h2>Thank you for your order!</h2>
<p>Order ID: ${payment.orderId}</p>
<p>Amount: ${formatCurrency(payment.amount, payment.currencyCode)}</p>
`;
};
Display payment details from the
Success event:val state by checkout.state.collectAsStateWithLifecycle()
LaunchedEffect(state) {
when (val s = state) {
is PrimerCheckoutState.Success -> {
val payment = s.checkoutData.payment
showSuccessScreen(
orderId = payment.orderId,
paymentId = payment.id,
)
}
is PrimerCheckoutState.Failure -> {
Log.e("Checkout", "Failed: ${s.error.diagnosticsId}")
}
else -> Unit
}
}
PrimerCheckoutSheet(checkout = checkout)
Display payment details from the success result:
PrimerCheckout(
clientToken: clientToken,
onCompletion: { state in
switch state {
case .success(let result):
showSuccessScreen(paymentId: result.paymentId)
case .failure(let error):
print("Failed [\(error.errorId)]: \(error.diagnosticsId)")
default:
break
}
}
)
Handle checkout dismissal
- Web
- Android
- iOS
primer.onPaymentSuccess = () => {
const successEl = document.getElementById('success-message');
successEl.classList.add('visible');
// Hide checkout form
document.querySelector('primer-checkout').style.display = 'none';
};
Use the
onDismiss callback to detect when the checkout sheet is closed:PrimerCheckoutSheet(
checkout = checkout,
onDismiss = {
navController.popBackStack()
},
)
onDismiss fires after the sheet closes. If you already navigated away when observing PrimerCheckoutState.Success, guard against double navigation.Handle the
.dismissed case to detect when the user closes the checkout:PrimerCheckout(
clientToken: clientToken,
onCompletion: { state in
switch state {
case .success:
withAnimation { showSuccess = true }
case .dismissed:
// User closed the checkout
break
default:
break
}
}
)
See also
Redirect after payment
Navigate to a confirmation page after payment
Error handling
Handle payment failures and display error messages