Skip to main content

Klarna

Klarna renders its native payment widget inside your screen. Your Pay button submits: /validate runs first, then Klarna's own authorization inside the same call.

Setup​

Artifacteu.purse:headless-checkout-klarna (brings the Klarna Mobile SDK)
RepositoryKlarna's SDK is not on Maven Central: add https://x.klarnacdn.net/mobile-sdk/
DashboardKlarna installments activated on the entity. The Klarna client token reaches the app through /init
ManifestA deep link on your checkout Activity, with launchMode="singleTask"
KeysNone in the app
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven("https://x.klarnacdn.net/mobile-sdk/")
}
}
// app/build.gradle.kts
dependencies {
implementation("eu.purse:headless-checkout-klarna:${SDK_VERSION}")
}

Klarna's widget can open a banking or identity app and must return to the same Activity instance that hosts it. Declare the deep link on your checkout Activity; singleTask guarantees no second instance is created:

<activity android:name=".CheckoutActivity" android:launchMode="singleTask" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="${applicationId}.klarna" android:host="return" />
</intent-filter>
</activity>

rememberPaymentElement hands Klarna "{packageName}.klarna://return" by default, which matches this filter. If you declare another scheme, pass it as klarnaReturnUrl.

Render and pay​

Create the element when the shopper selects Klarna. Once PaymentElementUi has attached the widget's container, the SDK runs POST /init to obtain the client token, then loads the widget.

val element = rememberPaymentElement(checkout, klarnaMethod, listener) // klarnaReturnUrl = "{packageName}.klarna://return"
LaunchedEffect(klarnaMethod.id) { checkout.setPrimary(klarnaMethod) }
PaymentElementUi(element, Modifier.fillMaxWidth()) // the native widget, sized by Klarna
Button(onClick = { element.submit() }, enabled = element.ready) { Text("Pay with Klarna") }

element.ready turns true once the widget loaded. submit() runs /validate, and only if it succeeds asks Klarna to authorize (and finalize when Klarna requires it). If /validate fails, Klarna is never asked.

Outcomes​

OutcomeWhen
Completed/validate succeeded and Klarna authorized
ReturnedFromRedirectKlarna sent the shopper to an external bank or identity step and they came back. Not an outcome. Show a processing state; your backend confirms the payment
CanceledKlarna declined the authorization, or the external step was dismissed. Not an error
FailedThe widget failed to load, /init or /validate failed, or Klarna reported an outright error

A Failed before any submit (the widget did not load) is not a failed payment: the method is disabled with PARTNER_UI_FATAL_ERROR, leave the shopper able to pick another method.

Instalment simulation​

A Klarna method flagged simulable can show the schedule before the shopper selects it: Instalment simulation.

Troubleshooting​

SymptomCause
The widget shows a generic "see our terms" card, no instalment breakdownKlarna offers no instalment product for this amount and market. A Klarna-side configuration, not an SDK issue
Failed with API_ERROR, message mentions no klarna_client_token/init did not create a Klarna session for this item. Check the method's configuration
Failed with PARTNER_UI_ERROR mentioning ERROR_INVALID_CLIENT_TOKENA stale token: the session expired between selection and payment. Refresh the session
Canceled right after tapping Pay/validate succeeded but Klarna declined the authorization
After a bank app step, the widget is gone and a new screen instance openedMissing launchMode="singleTask" or a scheme that does not match klarnaReturnUrl
Gradle cannot resolve com.klarna.mobile:sdkKlarna's Maven repository is missing from settings.gradle.kts
The method is listed but has no UI, submit() fails with METHOD_NOT_IMPLEMENTEDThe -klarna artifact is missing. See Payment methods